File Coverage

blib/lib/B/XPath.pm
Criterion Covered Total %
statement 159 221 71.9
branch 20 32 62.5
condition 4 6 66.6
subroutine 44 71 61.9
pod 3 3 100.0
total 230 333 69.0


line stmt bran cond sub pod time code
1             package B::XPath;
2              
3 2     2   26329 use strict;
  2         6  
  2         89  
4 2     2   12 use warnings;
  2         5  
  2         104  
5              
6             our $VERSION = '0.01';
7              
8 2     2   12 use B;
  2         17  
  2         108  
9 2     2   11 use Scalar::Util 'blessed';
  2         4  
  2         775  
10              
11             sub fetch_root
12             {
13 1     1 1 861 my ($class, $sub) = @_;
14 1         15 my $op = B::svref_2object( $sub )->ROOT();
15 1         4 my $op_class = $class->find_op_class( $op );
16 1         11 return $op_class->create( root => $op );
17             }
18              
19             sub fetch_main_root
20             {
21 0     0 1 0 my ($class) = @_;
22 0         0 my $op = B::main_root();
23 0         0 my $op_class = $class->find_op_class( $op );
24 0         0 return $op_class->create( root => $op );
25             }
26              
27             sub find_op_class
28             {
29 12     12 1 20 my ($class, $op) = @_;
30 12         36 my $node_class = blessed( $op );
31 12         79 $node_class =~ s/(::\w+)$/::XPath$1/;
32 12         30 return $node_class;
33             }
34              
35             package B::XPath::Node;
36              
37             use Class::XPath
38 2         81 get_name => 'name',
39             get_parent => 'parent',
40             get_root => 'get_root',
41             get_children => 'get_children',
42             get_attr_names => 'get_attr_names',
43             get_attr_value => 'get_attr_value',
44 2     2   2231 get_content => 'get_content';
  2         6148  
45              
46             sub create
47             {
48 12     12   66 my ($class, %args) = @_;
49 12         18 my $self = \%args;
50 12 100       38 @args{qw( op root )} = ($args{root}, $self) unless $args{op};
51              
52 12         27 bless $self, $class;
53              
54 12         52 $self->create_children();
55 12         34 return $self;
56             }
57              
58             sub get_root
59             {
60 12     12   13 my $self = shift;
61 12         65 return $self->{root};
62             }
63              
64             sub op
65             {
66 27     27   33 my $self = shift;
67 27         153 return $self->{op};
68             }
69              
70             sub parent
71             {
72 2     2   5 my $self = shift;
73 2 50       8 return unless exists $self->{parent};
74 2         7 return $self->{parent};
75             }
76              
77             sub create_children
78             {
79 12     12   14 my $self = shift;
80 12         42 my $root = $self->get_root();
81 12         28 my $kids = $self->{children} = [];
82              
83 12         36 for my $kid ($self->kids())
84             {
85 11         28 my $kid_class = B::XPath->find_op_class( $kid );
86 11         62 push @$kids, $kid_class->create(
87             op => $kid,
88             root => $root,
89             parent => $self,
90             );
91             }
92             }
93              
94             sub kids
95             {
96 7     7   26 my $self = shift;
97 7 50       20 return unless $self->name() eq 'null';
98             }
99              
100             sub get_children
101             {
102 6     6   965 my $self = shift;
103 6 50       23 return unless $self->{children};
104 6         6 return @{ $self->{children} };
  6         27  
105             }
106              
107             sub get_name
108             {
109 7     7   4596 my $self = shift;
110 7         30 return $self->name();
111             }
112              
113 0     0   0 sub DESTROY {}
114              
115             sub AUTOLOAD
116             {
117 1     1   19 our $AUTOLOAD;
118 1         2 my $self = $_[0];
119 1         10 my ($method) = $AUTOLOAD =~ /::(\w+)$/;
120 1         4 my $op = $self->op();
121              
122 1 50       12 die "Unimplemented method $method for $self\n" unless $op->can( $method );
123 1     4   7 my $sub = sub { shift->op()->$method() };
  4         13  
124 2     2   2151 no strict 'refs';
  2         9  
  2         983  
125 1         2 *{ Scalar::Util::blessed( $self ) . '::' . $method } = $sub;
  1         15  
126 1         7 goto &$sub;
127             }
128              
129             sub get_attr_value
130             {
131 0     0   0 my ($self, $attr) = @_;
132 0         0 my $op = $self->op();
133 0 0       0 return unless $op->can( $attr );
134 0         0 return $op->$attr();
135             }
136              
137             sub get_nextstate
138             {
139 2     2   5 my $self = shift;
140 2 50       9 return $self->{nextstate} if $self->{nextstate};
141 2         16 $self->{nextstate} = $self->find_nextstate();
142             }
143              
144             sub find_nextstate
145             {
146 2     2   3 my $self = shift;
147 2         17 my $parent = $self->parent();
148              
149 2         3 my $nextstate;
150              
151 2         7 for my $sibling ( $parent->get_children() )
152             {
153 6 100       23 last if $sibling eq $self;
154 4 100       11 next unless $sibling->name() eq 'nextstate';
155 3         7 $nextstate = $sibling;
156             }
157              
158 2 50       12 return $nextstate if defined $nextstate;
159 0         0 return $parent->find_nextstate();
160             }
161              
162             sub get_line
163             {
164 0     0   0 my $self = shift;
165 0         0 my $nextstate = $self->get_nextstate();
166 0         0 return $nextstate->line();
167             }
168              
169             sub get_file
170             {
171 0     0   0 my $self = shift;
172 0         0 my $nextstate = $self->get_nextstate();
173 0         0 return $nextstate->file();
174             }
175              
176             sub name
177             {
178 17     17   21 my $self = shift;
179 17         41 my $name = $self->op()->name();
180 17 50       106 return $name unless $name eq 'null';
181 0         0 return substr( B::ppname( $self->targ() ), 3 );
182             }
183              
184             package B::XPath::NULL;
185              
186 2     2   15 use base 'B::XPath::Node';
  2         3  
  2         1570  
187              
188             package B::XPath::OP;
189              
190 2     2   20 use base 'B::XPath::Node';
  2         4  
  2         967  
191              
192             sub get_attr_names
193             {
194 0     0   0 return qw( sibling ppaddr desc targ type opt static flags private spare );
195             }
196              
197             sub get_content
198             {
199 0     0   0 my $self = shift;
200 0         0 return $self->name();
201             }
202              
203             package B::XPath::UNOP;
204              
205 2     2   16 use base 'B::XPath::Node';
  2         4  
  2         1276  
206              
207             sub kids
208             {
209 3     3   5 my $self = shift;
210 3         21 my $op = $self->op();
211 3         19 my $first = $op->first();
212              
213 3         8 my @kids = $first;
214 3         4 my $sibling = $first;
215              
216 3         42 while ($sibling = $sibling->sibling())
217             {
218 5 50 66     56 if ($sibling->isa( 'B::NULL' ) and $sibling->can( 'kids' ))
219             {
220 0         0 push @kids, $sibling->kids();
221             }
222 5 100       19 last if $sibling->isa( 'B::NULL' );
223 2         14 push @kids, $sibling;
224             }
225              
226 3         11 return @kids;
227             }
228              
229             package B::XPath::BINOP;
230              
231 2     2   12 use base 'B::XPath::UNOP';
  2         4  
  2         1142  
232              
233             sub kids
234             {
235 2     2   3 my $self = shift;
236 2         7 return $self->SUPER::kids();
237             }
238              
239             package B::XPath::LOGOP;
240              
241 2     2   13 use base 'B::XPath::UNOP';
  2         82  
  2         1527  
242              
243             sub kids
244             {
245 0     0   0 my $self = shift;
246 0         0 return $self->SUPER::kids(), $self->other();
247             }
248              
249             package B::XPath::LISTOP;
250              
251 2     2   16 use base 'B::XPath::BINOP';
  2         4  
  2         1575  
252              
253             sub kids
254             {
255 2     2   4 my $self = shift;
256 2         8 my $op = $self->op();
257 2         10 my $first = $op->first();
258 2         11 my $last = $op->last();
259              
260 2         4 my @kids = $first;
261 2         5 my $sibling = $first;
262              
263 2         19 while ($sibling = $sibling->sibling())
264             {
265 6 50 66     51 if ($sibling->isa( 'B::NULL' ) and $sibling->can( 'kids' ))
266             {
267 0         0 push @kids, $sibling->kids();
268             }
269 6 100       26 last if $sibling->isa( 'B::NULL' );
270 4         7 push @kids, $sibling;
271 4 50       28 last if $sibling == $last;
272             }
273              
274 2         21 return @kids;
275             }
276              
277             package B::XPath::LOOP;
278              
279 2     2   74 use base 'B::XPath::LISTOP';
  2         5  
  2         1655  
280              
281             sub kids
282             {
283 0     0   0 my $self = shift;
284 0         0 my $op = $self->op();
285 0         0 return $op->nextop(), $op->lastop(), $op->redoop();
286             }
287              
288             package B::XPath::COP;
289              
290 2     2   28 use base 'B::XPath::OP';
  2         3  
  2         1242  
291              
292             sub get_attr_names
293             {
294 0     0   0 my $self = shift;
295 0         0 return $self->SUPER::get_attr_names(),
296             qw( label stash stashpv file cop_seq arybase line warnings io );
297             }
298              
299             package B::XPath::SVOP;
300              
301             # this package is different; SVOPs contain GVs/SVs
302             # however, they don't look like it in the optree
303             # op() here thus delegates all calls to the contained GV
304              
305 2     2   12 use base 'B::XPath::OP';
  2         4  
  2         1177  
306              
307             # the parent name() uses op(), which is wrong here
308             sub name
309             {
310 1     1   10 return $_[0]->{op}->name();
311             }
312              
313             # hey, these look like GV attributes!
314             sub get_attr_names
315             {
316 0     0     my $self = shift;
317 0           my @names = $self->SUPER::get_attr_names();
318 0           return @names,
319             qw( NAME SAFENAME STASH SV IO FORM AV HV EGV CV CVGEN LINE FILE FILEGV
320             GvREFCNT FLAGS );
321             }
322              
323             # you don't want me, you want my GV
324             sub op
325             {
326 0     0     my $self = shift;
327 0           return $self->{op}->gv();
328             }
329              
330             package B::XPath::PADOP;
331              
332 2     2   12 use base 'B::XPath::OP';
  2         4  
  2         1171  
333              
334             sub get_attr_names
335             {
336 0     0     my $self = shift;
337 0           return $self->SUPER::get_attr_names(), qw( padix );
338             }
339              
340             package B::XPath::PVOP;
341              
342 2     2   13 use base 'B::XPath::OP';
  2         3  
  2         1261  
343              
344             sub get_attr_names
345             {
346 0     0     my $self = shift;
347 0           return $self->SUPER::get_attr_names(), qw( pv );
348             }
349              
350             package B::XPath::SV;
351              
352 2     2   121 use base 'B::XPath::Node';
  2         5  
  2         1347  
353              
354             sub get_name
355             {
356 0     0     my $self = shift;
357 0           return $self->name();
358             }
359              
360 0     0     sub get_root {}
361 0     0     sub get_content {}
362 0     0     sub get_attr_names {}
363              
364             package B::XPath::IV;
365              
366 2     2   13 use base 'B::XPath::SV';
  2         5  
  2         1193  
367              
368             sub get_content
369             {
370 0     0     my $self = shift;
371 0           my $op = shift;
372 0           return $op->int_value();
373             }
374              
375             sub get_attr_names
376             {
377 0     0     my $self = shift;
378 0           my @names = $self->SUPER::get_attr_names();
379 0           return @names, qw( needs64bits packiv );
380             }
381              
382             package B::XPath::NV;
383              
384 2     2   13 use base 'B::XPath::IV';
  2         28  
  2         1155  
385              
386             sub get_content
387             {
388 0     0     my $self = shift;
389 0           return $self->op()->NV();
390             }
391              
392             package B::XPath::RV;
393              
394 2     2   13 use base 'B::XPath::SV';
  2         5  
  2         1177  
395              
396             sub get_content
397             {
398 0     0     my $self = shift;
399 0           return $self->op()->RV();
400             }
401              
402             package B::XPath::PV;
403              
404 2     2   12 use base 'B::XPath::SV';
  2         4  
  2         1113  
405              
406 0     0     sub name { 'pv' }
407              
408             sub get_content
409             {
410 0     0     my $self = shift;
411 0           return $self->op()->PV();
412             }
413              
414             package B::XPath::PVNV;
415              
416 2     2   11 use base qw( B::XPath::PV B::XPath::NV );
  2         4  
  2         2500  
417              
418             package B::XPath::PVMG;
419              
420 2     2   17 use base 'B::XPath::PVNV';
  2         589  
  2         1318  
421              
422             package B::XPath::GV;
423              
424 2     2   13 use base 'B::XPath::PVMG';
  2         4  
  2         1462  
425              
426 0     0     sub name { 'gv' }
427              
428             sub get_content
429             {
430 0     0     my $self = shift;
431 0           return $self->op()->SAFENAME();
432             }
433              
434             sub get_attr_names
435             {
436 0     0     my $self = shift;
437 0           my @names = $self->SUPER::get_attr_names();
438 0           return @names,
439             qw( NAME SAFENAME STASH SV IO FORM AV HV EGV CV CVGEN LINE FILE FILEGV
440             GvREFCNT FLAGS );
441             }
442              
443             1;
444             __END__