File Coverage

blib/lib/Nice/Try.pm
Criterion Covered Total %
statement 486 622 78.1
branch 222 406 54.6
condition 99 172 57.5
subroutine 36 45 80.0
pod 4 7 57.1
total 847 1252 67.6


line stmt bran cond sub pod time code
1             ##----------------------------------------------------------------------------
2             ## A real Try Catch Block Implementation Using Perl Filter - ~/lib/Nice/Try.pm
3             ## Version v1.3.3
4             ## Copyright(c) 2023 DEGUEST Pte. Ltd.
5             ## Author: Jacques Deguest
6             ## Created 2020/05/17
7             ## Modified 2023/01/13
8             ## All rights reserved
9             ##
10             ## This program is free software; you can redistribute it and/or modify it
11             ## under the same terms as Perl itself.
12             ##----------------------------------------------------------------------------
13             package Nice::Try;
14             BEGIN
15             {
16 24     24   376 require 5.16.0;
17 24     24   2609361 use strict;
  24         317  
  24         771  
18 24     24   127 use warnings;
  24         45  
  24         773  
19 24     24   139 use warnings::register;
  24         47  
  24         3538  
20 24         3052 use vars qw(
21             $CATCH $DIED $EXCEPTION $FINALLY $HAS_CATCH @RETVAL $SENTINEL $TRY $WANTARRAY
22             $VERSION $ERROR
23 24     24   179 );
  24         45  
24             # XXX Only for debugging
25             # use Devel::Confess;
26 24     24   14140 use PPI;
  24         2986226  
  24         1172  
27 24     24   12459 use Filter::Util::Call;
  24         20116  
  24         1977  
28 24     24   191 use Scalar::Util ();
  24         69  
  24         427  
29 24     24   141 use List::Util ();
  24         62  
  24         489  
30 24     24   12055 use Want ();
  24         46708  
  24         1850  
31 24         104 our $VERSION = 'v1.3.3';
32 24         53 our $ERROR;
33 24         571 our( $CATCH, $DIED, $EXCEPTION, $FINALLY, $HAS_CATCH, @RETVAL, $SENTINEL, $TRY, $WANTARRAY );
34             }
35              
36 24     24   133 use strict;
  24         78  
  24         497  
37 24     24   142 use warnings;
  24         52  
  24         49463  
38              
39             # Taken from Try::Harder version 0.005
40             our $SENTINEL = bless( {} => __PACKAGE__ . '::SENTINEL' );
41              
42             sub import
43             {
44 25     25   819 my( $this, @arguments ) = @_ ;
45 25         74 my $class = CORE::caller();
46 25         175 my $hash = { @arguments };
47 25 50       156 $hash->{debug} = 0 if( !CORE::exists( $hash->{debug} ) );
48 25 50       146 $hash->{no_filter} = 0 if( !CORE::exists( $hash->{no_filter} ) );
49 25 50       86 $hash->{debug_code} = 0 if( !CORE::exists( $hash->{debug_code} ) );
50 25 50       87 $hash->{debug_dump} = 0 if( !CORE::exists( $hash->{debug_dump} ) );
51 25 50       78 $hash->{dont_want} = 0 if( !CORE::exists( $hash->{dont_want} ) );
52             # We check if we are running under tie and if so we cannot use Want features,
53             # because they would trigger a segmentation fault.
54 25         44 $hash->{is_tied} = 0;
55 25 50 33     736 if( $class->can( 'TIESCALAR' ) || $class->can( 'TIEHASH' ) || $class->can( 'TIEARRAY' ) )
      33        
56             {
57 0         0 $hash->{is_tied} = 1;
58             }
59 25         161 require overload;
60 25 50       172 $hash->{is_overloaded} = overload::Overloaded( $class ) ? 1 : 0;
61 25         1924 $hash->{no_context} = 0;
62             # 2021-05-17 (Jacques): the following was a bad idea as it was indiscriminate and
63             # would also affect use of caller outside of try-catch blocks
64             # *{"${class}::caller"} = \&{"Nice::Try::caller"};
65 25   33     230 filter_add( bless( $hash => ( ref( $this ) || $this ) ) );
66             }
67              
68             sub unimport
69             {
70 0     0   0 filter_del();
71             }
72              
73             sub caller($;$)
74             {
75 6     6 1 27 my $where = shift( @_ );
76 6         9 my $n = shift( @_ );
77             # Offsetting our internal call frames
78 6         22 my $map =
79             {
80             try => 3,
81             catch => 3,
82             finally => 5,
83             };
84 6 100       54 my @info = defined( $n ) ? CORE::caller( int( $n ) + $map->{ $where } ) : CORE::caller( 1 + $map->{ $where } );
85 6         35 return( @info );
86             }
87              
88 3     3 0 1866 sub caller_try { return( &Nice::Try::caller( try => @_ ) ); }
89              
90 1     1 0 2445 sub caller_catch { return( &Nice::Try::caller( catch => @_ ) ); }
91              
92 2     2 0 12 sub caller_finally { return( &Nice::Try::caller( finally => @_ ) ); }
93              
94             sub filter
95             {
96 43     43 1 79015 my( $self ) = @_ ;
97 43         103 my( $status, $last_line );
98 43         84 my $line = 0;
99 43         83 my $code = '';
100 43 50       325 if( $self->{no_filter} )
101             {
102 0         0 filter_del();
103 0         0 $status = 1;
104 0 0       0 $self->_message( 3, "Skiping filtering." ) if( $self->{debug} >= 3 );
105 0         0 return( $status );
106             }
107 43         431 while( $status = filter_read() )
108             {
109             # Error
110 2489 50       3799 if( $status < 0 )
111             {
112 0 0       0 $self->_message( 3, "An error occurred in fiilter, aborting." ) if( $self->{debug} >= 3 );
113 0         0 return( $status );
114             }
115 2489         2808 $line++;
116             # if( /^__(?:DATA|END)__/ )
117             # {
118             # $last_line = $_;
119             # last;
120             # }
121 2489         3148 $code .= $_;
122 2489         5367 $_ = '';
123             }
124 43 100       42591 return( $line ) if( !$line );
125 25 50       86 unless( $status < 0 )
126             {
127             # $self->_message( 5, "Processing at line $line code:\n$code" );
128             # 2021-06-05 (Jacques): fixes the issue No. 3
129             # Make sure there is at least a space at the beginning
130 25         192 $code = ' ' . $code;
131 25 50       138 $self->_message( 4, "Processing $line lines of code." ) if( $self->{debug} >= 4 );
132 25   50     429 my $doc = PPI::Document->new( \$code, readonly => 1 ) || die( "Unable to parse: ", PPI::Document->errstr, "\n$code\n" );
133             # Remove pod
134             # $doc->prune('PPI::Token::Pod');
135 25 50       2385892 $self->_browse( $doc ) if( $self->{debug_dump} );
136 25 100       177 if( $doc = $self->_parse( $doc ) )
137             {
138 21         242 $_ = $doc->serialize;
139             # $doc->save( "./dev/debug-parsed.pl" );
140             # $status = 1;
141             }
142             # Rollback
143             else
144             {
145             # $self->_message( 5, "Nothing found, restoring code to '$code'" );
146 4         1095 $_ = $code;
147             # $status = -1;
148             # filter_del();
149             }
150 25 50       120893 if( CORE::length( $last_line ) )
151             {
152 0         0 $_ .= $last_line;
153             }
154             }
155 25 50       61156 unless( $status <= 0 )
156             {
157 0         0 while( $status = filter_read() )
158             {
159 0         0 $self->_message( 4, "Reading more line: $_" );
160 0 0       0 return( $status ) if( $status < 0 );
161 0         0 $line++;
162             }
163             }
164             # $self->_message( 3, "Returning status '$line' with \$_ set to '$_'." );
165 25 50       201 if( $self->{debug_file} )
166             {
167 0 0       0 if( open( my $fh, ">$self->{debug_file}" ) )
168             {
169 0         0 binmode( $fh, ':utf8' );
170 0         0 print( $fh $_ );
171 0         0 close( $fh );
172             }
173             }
174             # filter_del();
175 25         24135 return( $line );
176             }
177              
178             sub implement
179             {
180 0     0 1 0 my $self = shift( @_ );
181 0         0 my $code = shift( @_ );
182 0 0 0     0 return( $code ) if( !CORE::defined( $code ) || !CORE::length( $code ) );
183 0 0       0 unless( ref( $self ) )
184             {
185 0 0 0     0 my $opts = ( !@_ || !defined( $_[0] ) )
    0          
    0          
186             ? {}
187             : ref( $_[0] ) eq 'HASH'
188             ? shift( @_ )
189             : !( @_ % 2 )
190             ? { @_ }
191             : {};
192 0         0 for( qw( debug no_context no_filter debug_code debug_dump debug_file dont_want is_tied is_overloaded ) )
193             {
194 0   0     0 $opts->{ $_ } //= 0;
195             }
196 0         0 $self = bless( $opts => $self );
197             }
198             # 2021-06-05 (Jacques): fixes the issue No. 3
199             # Make sure there is at least a space at the beginning
200 0         0 $code = ' ' . $code;
201 0 0       0 $self->_message( 4, "Processing ", CORE::length( $code ), " bytes of code." ) if( $self->{debug} >= 4 );
202 0   0     0 my $doc = PPI::Document->new( \$code, readonly => 1 ) || die( "Unable to parse: ", PPI::Document->errstr, "\n$code\n" );
203 0 0       0 $self->_browse( $doc ) if( $self->{debug_dump} );
204 0 0       0 if( $doc = $self->_parse( $doc ) )
205             {
206 0         0 $code = $doc->serialize;
207             }
208 0         0 return( $code );
209             }
210              
211             sub _browse
212             {
213 0     0   0 my $self = shift( @_ );
214 0         0 my $elem = shift( @_ );
215 0   0     0 my $level = shift( @_ ) || 0;
216 0 0       0 if( $self->{debug} >= 4 )
217             {
218 0         0 $self->_message( 4, "Checking code: ", $self->_serialize( $elem ) );
219 0         0 $self->_messagef( 4, "PPI element of class %s has children property '%s'.", $elem->class, $elem->{children} );
220             }
221 0 0       0 return if( !$elem->children );
222 0         0 foreach my $e ( $elem->elements )
223             {
224 0         0 printf( STDERR "%sElement: [%d] class %s, value %s\n", ( '.' x $level ), $e->line_number, $e->class, $e->content );
225 0 0 0     0 if( $e->can('children') && $e->children )
226             {
227 0         0 $self->_browse( $e, $level + 1 );
228             }
229             }
230             }
231              
232             sub _error
233             {
234 0     0   0 my $self = shift( @_ );
235 0 0       0 if( @_ )
236             {
237 0 0       0 my $txt = join( '', map( ref( $_ ) eq 'CODE' ? $_->() : $_, @_ ) );
238 0         0 $txt =~ s/[\015\012]+$//g;
239 0         0 $ERROR = $txt;
240 0 0       0 CORE::warn( "$txt\n" ) if( warnings::enabled );
241 0         0 return;
242             }
243 0         0 return( $ERROR );
244             }
245              
246             sub _message
247             {
248 0     0   0 my $self = shift( @_ );
249 0 0       0 my $level = $_[0] =~ /^\d+$/ ? shift( @_ ) : 0;
250 0 0       0 return if( $self->{debug} < $level );
251 0         0 my @data = @_;
252 0         0 my $stackFrame = 0;
253 0         0 my( $pkg, $file, $line, @otherInfo ) = CORE::caller( $stackFrame );
254 0         0 my $sub = ( CORE::caller( $stackFrame + 1 ) )[3];
255 0         0 my $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
256 0 0       0 my $txt = "${pkg}::${sub2}( $self ) [$line]: " . join( '', map( ref( $_ ) eq 'CODE' ? $_->() : $_, @data ) );
257 0         0 $txt =~ s/\n$//gs;
258 0         0 $txt = '## ' . join( "\n## ", split( /\n/, $txt ) );
259 0         0 CORE::print( STDERR $txt, "\n" );
260             }
261              
262             sub _messagef
263             {
264 96     96   4767 my $self = shift( @_ );
265 96 50       520 my $level = $_[0] =~ /^\d+$/ ? shift( @_ ) : 0;
266 96 50       314 return if( $self->{debug} < $level );
267 0         0 my @data = @_;
268 0         0 my $stackFrame = 0;
269 0         0 my $fmt = shift( @data );
270 0         0 my( $pkg, $file, $line, @otherInfo ) = CORE::caller( $stackFrame );
271 0         0 my $sub = ( CORE::caller( $stackFrame + 1 ) )[3];
272 0         0 my $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
273 0         0 for( @data )
274             {
275 0 0       0 next if( ref( $_ ) );
276 0         0 s/\b\%/\x{025}/g;
277             }
278 0 0       0 my $txt = "${pkg}::${sub2}( $self ) [$line]: " . sprintf( $fmt, map( ref( $_ ) eq 'CODE' ? $_->() : $_, @data ) );
279 0         0 $txt =~ s/\n$//gs;
280 0         0 $txt = '## ' . join( "\n## ", split( /\n/, $txt ) );
281 0         0 CORE::print( STDERR $txt, "\n" );
282             }
283              
284             sub _parse
285             {
286 267     267   523 my $self = shift( @_ );
287 267         424 my $elem = shift( @_ );
288 24     24   266 no warnings 'uninitialized';
  24         93  
  24         81393  
289 267 50 33     2009 if( !Scalar::Util::blessed( $elem ) || !$elem->isa( 'PPI::Node' ) )
290             {
291 0         0 return( $self->_error( "Element provided to parse is not a PPI::Node object" ) );
292             }
293            
294             my $ref = $elem->find(sub
295             {
296 25549     25549   445154 my( $top, $this ) = @_;
297 25549   100     44165 return( $this->class eq 'PPI::Statement' && substr( $this->content, 0, 3 ) eq 'try' );
298 267         2030 });
299 267 50       4840 return( $self->_error( "Failed to find any try-catch clause: $@" ) ) if( !defined( $ref ) );
300 267 50 66     1023 $self->_messagef( 4, "Found %d match(es)", scalar( @$ref ) ) if( $ref && ref( $ref ) && $self->{debug} >= 4 );
      66        
301 267 100 66     1343 return if( !$ref || !scalar( @$ref ) );
302            
303             # 2020-09-13: PPI will return 2 or more consecutive try-catch block as 1 statement
304             # It does not tell them apart, so we need to post process the result to effectively search within for possible for other try-catch blocks and update the @$ref array consequently
305             # Array to contain the new version of the $ref array.
306 25         106 my $alt_ref = [];
307 25 50       165 $self->_message( 3, "Checking for consecutive try-catch blocks in results found by PPI" ) if( $self->{debug} >= 3 );
308 25         120 foreach my $this ( @$ref )
309             {
310 118         1247 my( @block_children ) = $this->children;
311 118 50       1114 next if( !scalar( @block_children ) );
312 118         206 my $tmp_ref = [];
313             ## to contain all the nodes to move
314 118         179 my $tmp_nodes = [];
315 118         172 my $prev_sib = $block_children[0];
316 118         195 push( @$tmp_nodes, $prev_sib );
317 118         156 my $sib;
318 118         420 while( $sib = $prev_sib->next_sibling )
319             {
320             # We found a try-catch block. Move the buffer to $alt_ref
321 1538 100 100     37989 if( $sib->class eq 'PPI::Token::Word' && $sib->content eq 'try' )
322             {
323             # Look ahead for a block...
324 2         31 my $next = $sib->snext_sibling;
325 2 50 33     101 if( $next && $next->class eq 'PPI::Structure::Block' )
326             {
327 2 50       17 $self->_message( 3, "Found consecutive try-block." ) if( $self->{debug} >= 3 );
328             # Push the previous statement $st to the stack $alt_ref
329 2 50       7 $self->_messagef( 3, "Saving previous %d nodes collected.", scalar( @$tmp_nodes ) ) if( $self->{debug} >= 3 );
330 2         5 push( @$tmp_ref, $tmp_nodes );
331 2         4 $tmp_nodes = [];
332             }
333             }
334 1538         7010 push( @$tmp_nodes, $sib );
335 1538         3125 $prev_sib = $sib;
336             }
337 118 50       3711 $self->_messagef( 3, "Saving last %d nodes collected.", scalar( @$tmp_nodes ) ) if( $self->{debug} >= 3 );
338 118         224 push( @$tmp_ref, $tmp_nodes );
339 118 50       296 $self->_messagef( 3, "Found %d try-catch block(s) in initial PPI result.", scalar( @$tmp_ref ) ) if( $self->{debug} >= 3 );
340             # If we did find consecutive try-catch blocks, we add each of them after the nominal one and remove the nominal one after. The nominal one should be empty by then
341 118 100       276 if( scalar( @$tmp_ref ) > 1 )
342             {
343 2         5 my $last_obj = $this;
344 2         3 my $spaces = [];
345 2         7 foreach my $arr ( @$tmp_ref )
346             {
347 4 50       54 $self->_message( 3, "Adding statement block with ", scalar( @$arr ), " children after '$last_obj'" ) if( $self->{debug} >= 3 );
348             # 2021-06-05 (Jacques): Fixing issue No. 2:
349             # Find the last block that belongs to us
350 4 50       7 $self->_message( 4, "Checking first level objects collected." ) if( $self->{debug} >= 4 );
351 4         7 my $last_control = '';
352 4         15 my $last_block;
353 4         6 my $last = {};
354 4         8 foreach my $o ( @$arr )
355             {
356             # $self->_message( 4, "Found object '$o' of class '", $o->class, "' (", overload::StrVal( $o ), ")." );
357 57 100 100     256 if( $o->class eq 'PPI::Structure::Block' && $last_control )
    100          
358             {
359 8         53 $last->{block} = $o;
360 8         12 $last->{control} = $last_control;
361 8         13 $last_control = '';
362             }
363             elsif( $o->class eq 'PPI::Token::Word' )
364             {
365 11         91 my $ct = $o->content;
366 11 100 100     77 if( $ct eq 'try' || $ct eq 'catch' || $ct eq 'finally' )
      66        
367             {
368 8         17 $last_control = $o;
369             }
370             }
371             }
372             # $self->_message( 4, "Last control was '$last->{control}' and last block '$last->{block}' (", overload::StrVal( $last->{block} ), ")." );
373            
374             # Get the trailing insignificant elements at the end of the statement and move them out of the statement
375 4         28 my $insignificants = [];
376 4         10 while( scalar( @$arr ) > 0 )
377             {
378 25         953 my $o = $arr->[-1];
379             # $self->_message( 4, "Checking trailing object with class '", $o->class, "' and value '$o'" );
380             # 2021-06-05 (Jacques): We don't just look for the last block, because
381             # that was making a bad assumption that the last trailing block would be our
382             # try-catch block.
383             # Following issue No. 2 reported with a trailing anonymous subroutine,
384             # We remove everything up until our known last block that belongs to us.
385 25 100 100     50 last if( $o->class eq 'PPI::Structure::Block' && Scalar::Util::refaddr( $o ) eq Scalar::Util::refaddr( $last->{block} ) );
386 21         110 unshift( @$insignificants, pop( @$arr )->remove );
387             }
388 4 50       41 $self->_messagef( 3, "%d insignificant objects found.", scalar( @$insignificants ) ) if( $self->{debug} >= 3 );
389            
390 4         15 my $new_code = join( '', map( "$_", @$arr ) );
391             # $self->_message( 4, "New code is: '$new_code'" );
392             # 2021-06-05 (Jacques): It is unfortunately difficult to simply add a new PPI::Statement object
393             # Instead, we have PPI parse our new code and we grab what we need.
394 4         666 my $new_block = PPI::Document->new( \$new_code, readonly => 1 );
395             # $self->_message( 4, "New block code is: '$new_block'" );
396             # $self->_browse( $new_block );
397 4         18856 my $st = $new_block->{children}->[0]->remove;
398             # $self->_message( 4, "Statemnt now contains: '$st'" );
399            
400             # $self->_messagef( 3, "Adding the updated statement objects with %d children.", scalar( @$arr ) );
401 4         171 foreach my $o ( @$arr )
402             {
403             # We remove the object from its parent, now that it has become useless
404 36   50     992 my $old = $o->remove || die( "Unable to remove element '$o'\n" );
405             }
406 4         115 my $err = '';
407 4 0       12 $self->_messagef( 3, "Adding the statement object after last object '%s' of class '%s' with parent with class '%s'.", Scalar::Util::refaddr( $last_obj ), ( defined( $last_obj ) ? $last_obj->class : 'undefined class' ), ( defined( $last_obj ) ? $last_obj->parent->class : 'undefined parent class' ) ) if( $self->{debug} >= 3 );
    0          
    50          
408 4 50       9 $self->_message( 4, "In other word, adding:\n'$st'\nAFTER:\n'$last_obj'" ) if( $self->{debug} >= 4 );
409             # my $rc = $last_obj->insert_after( $st );
410 4         16 my $rc;
411 4 100       13 if( $last_obj->class eq 'PPI::Token::Whitespace' )
412             {
413 2         15 $rc = $last_obj->__insert_after( $st );
414             }
415             else
416             {
417 2         18 $rc = $last_obj->insert_after( $st );
418             }
419            
420 4 50       189 if( !defined( $rc ) )
    50          
421             {
422 0         0 $err = sprintf( 'Object to be added after last try-block statement must be a PPI::Element. Class provided is \"%s\".', $st->class );
423             }
424             elsif( !$rc )
425             {
426 0         0 $err = sprintf( "Object of class \"%s\" could not be added after object '%s' of class '%s' with parent '%s' with class '%s': '$last_obj'.", $st->class, Scalar::Util::refaddr( $last_obj ), $last_obj->class, Scalar::Util::refaddr( $last_obj->parent ), $last_obj->parent->class );
427             }
428             else
429             {
430 4         6 $last_obj = $st;
431 4 50       10 if( scalar( @$insignificants ) )
432             {
433 4 50       11 $self->_messagef( 4, "Adding %d trailing insignificant objects after last element of class '%s'", scalar( @$insignificants ), $last_obj->class ) if( $self->{debug} >= 4 );
434 4         8 foreach my $o ( @$insignificants )
435             {
436 21 50       50 $self->_messagef( 4, "Adding trailing insignificant object of class '%s' after last element of class '%s'", $o->class, $last_obj->class ) if( $self->{debug} >= 4 );
437             ## printf( STDERR "Inserting object '%s' (%s) of type '%s' after object '%s' (%s) of type %s who has parent '%s' of type '%s'\n", overload::StrVal( $o ), Scalar::Util::refaddr( $o ), ref( $o ), overload::StrVal( $last_obj), Scalar::Util::refaddr( $last_obj ), ref( $last_obj ), overload::StrVal( $last_obj->parent ), ref( $last_obj->parent ) );
438             CORE::eval
439 21         29 {
440             $rc = $last_obj->insert_after( $o ) ||
441             do
442 21   33     66 {
443             warn( "Failed to insert object of class '", $o->class, "' before last object of class '", $st->class, "'\n" ) if( $self->{debug} );
444             };
445             };
446 21 50       1042 if( $@ )
    50          
    50          
447             {
448 0 0       0 if( ref( $o ) )
449             {
450 0 0       0 warn( "Failed to insert object of class '", $o->class, "' before last object of class '", $st->class, "': $@\n" ) if( $self->{debug} );
451             }
452             else
453             {
454 0 0       0 warn( "Was expecting an object to insert before last object of class '", $st->class, "', but instead got '$o': $@\n" ) if( $self->{debug} );
455             }
456             }
457             elsif( !defined( $rc ) )
458             {
459 0 0       0 warn( sprintf( 'Object to be added after last try-block statement must be a PPI::Element. Class provided is \"%s\".', $o->class ) ) if( $self->{debug} );
460             }
461             elsif( !$rc )
462             {
463 0 0       0 warn( sprintf( "Object of class \"%s\" could not be added after object of class '%s': '$last_obj'.", $o->class, $last_obj->class ) ) if( $self->{debug} );
464             }
465             ## printf( STDERR "Object inserted '%s' (%s) of class '%s' now has parent '%s' (%s) of class '%s'\n", overload::StrVal( $o ), Scalar::Util::refaddr( $o ), ref( $o ), overload::StrVal( $o->parent ), Scalar::Util::refaddr( $o->parent ), ref( $o->parent ) );
466 21 50       42 $o->parent( $last_obj->parent ) if( !$o->parent );
467 21         101 $last_obj = $o;
468             }
469             }
470             }
471 4 50       15 die( $err ) if( length( $err ) );
472 4         19 push( @$alt_ref, $st );
473             }
474 2         40 my $parent = $this->parent;
475             ## Completely destroy it; it is now replaced by our updated code
476 2         16 $this->delete;
477             }
478             else
479             {
480 116         447 push( @$alt_ref, $this );
481             }
482             }
483 25 50       391 $self->_messagef( 3, "Results found increased from %d to %d results.", scalar( @$ref ), scalar( @$alt_ref ) ) if( $self->{debug} >= 3 );
484 25 100       121 @$ref = @$alt_ref if( scalar( @$alt_ref ) > scalar( @$ref ) );
485            
486             # $self->_message( 3, "Script code is now:\n'$elem'" );
487            
488 25         98 foreach my $this ( @$ref )
489             {
490 120 50       17952 $self->_browse( $this ) if( $self->{debug} >= 5 );
491             # $self->_message( 4, "\$this is of class '", $this->class, "' and its parent of class '", $this->parent->class, "'." );
492 120         510 my $element_before_try = $this->previous_sibling;
493             # $self->_message( 4, "Is \$element_before_try defined ? ", defined( $element_before_try ) ? 'Yes' : 'No', "(", overload::StrVal( $element_before_try ), ") -> '$element_before_try'" );
494 120         2984 my $try_block_ref = [];
495             # Contains the finally block reference
496 120         195 my $fin_block_ref = [];
497 120         200 my $nodes_to_replace = [];
498 120         232 my $catch_def = [];
499             # Replacement data
500 120         180 my $repl = [];
501 120         176 my $catch_repl = [];
502            
503             # There is a weird bug in PPI that I have searched but could not find
504             # If I don't attempt to stringify, I may end up with a PPI::Statement object that has no children as an array reference
505 120         281 my $ct = "$this";
506             # $self->_message( 3, "Checking sibling elements for '$ct'" );
507 120         41158 my( @block_children ) = $this->children;
508 120 100       850 next if( !scalar( @block_children ) );
509 115         221 my $prev_sib = $block_children[0];
510 115         279 push( @$nodes_to_replace, $prev_sib );
511 115         207 my( $inside_catch, $inside_finally );
512 115         231 my $temp = {};
513             # Buffer of nodes found in between blocks
514 115         196 my $buff = [];
515             # Temporary new line counter between try-catch block so we can reproduce it and ensure proper reporting of error line
516 115         184 my $nl_counter = 0;
517 115         204 my $sib;
518 115         343 while( $sib = $prev_sib->next_sibling )
519             {
520             # $self->_messagef( 3, "Try sibling at line %d with class '%s': '%s'", $sib->line_number, $sib->class, $sib->content );
521 1455 100 100     37416 if( !scalar( @$try_block_ref ) )
    100 100        
    100 100        
    100          
    100          
    100          
522             {
523             # $self->_message( 3, "\tWorking on the initial try block." );
524 296 100 66     690 if( $sib->class eq 'PPI::Structure::Block' &&
    100 66        
      100        
525             substr( "$sib", 0, 1 ) eq "\{" &&
526             substr( "$sib", -1, 1 ) eq "\}" )
527             {
528 113         30909 $temp->{block} = $sib;
529 113         232 push( @$try_block_ref, $temp );
530 113         254 $temp = {};
531 113 50       292 if( scalar( @$buff ) )
532             {
533 113         244 push( @$nodes_to_replace, @$buff );
534 113         256 $buff = [];
535             }
536 113         220 push( @$nodes_to_replace, $sib );
537             }
538             elsif( $sib->class eq 'PPI::Token::Whitespace' && $sib->content =~ /[\015\012]+/ )
539             {
540             ## $self->_messagef( 4, "\tTry -> Found open new line at line %d", $sib->line_number );
541 68         1270 $temp->{open_curly_nl}++;
542 68         157 push( @$buff, $sib );
543             }
544             ## We skip anything else until we find that try block
545             else
546             {
547 115         3075 push( @$buff, $sib );
548 115         178 $prev_sib = $sib;
549 115         381 next;
550             }
551             }
552             elsif( $sib->class eq 'PPI::Token::Word' && $sib->content eq 'catch' )
553             {
554 129         1114 $inside_catch++;
555 129 100       326 if( scalar( @$buff ) )
556             {
557 125         299 push( @$nodes_to_replace, @$buff );
558 125         230 $buff = [];
559             }
560 129         216 push( @$nodes_to_replace, $sib );
561             }
562             elsif( $inside_catch )
563             {
564             # $self->_message( 3, "\tWorking on a catch block." );
565             # This is the catch list as in catch( $e ) or catch( Exception $e )
566 448 100 66     2143 if( $sib->class eq 'PPI::Structure::List' )
    100          
    100          
567             {
568 96         394 $temp->{var} = $sib;
569 96         159 push( @$nodes_to_replace, $sib );
570             }
571             elsif( $sib->class eq 'PPI::Structure::Block' )
572             {
573 129         778 $temp->{block} = $sib;
574 129 100       299 if( scalar( @$catch_def ) )
575             {
576 24         42 $catch_def->[-1]->{close_curly_nl} = $nl_counter;
577             }
578             else
579             {
580 105         205 $try_block_ref->[-1]->{close_curly_nl} = $nl_counter;
581             }
582 129         518 $nl_counter = 0;
583 129         216 push( @$catch_def, $temp );
584 129         222 $temp = {};
585 129         191 $inside_catch = 0;
586 129         254 push( @$nodes_to_replace, $sib );
587             }
588             elsif( $sib->class eq 'PPI::Token::Whitespace' && $sib->content =~ /[\015\012]+/ )
589             {
590             # $self->_messagef( 4, "\tCatch -> Found open new line at line %d", $sib->line_number );
591 87         1475 $temp->{open_curly_nl}++;
592 87         214 push( @$nodes_to_replace, $sib );
593             }
594             else
595             {
596 136         1768 push( @$nodes_to_replace, $sib );
597             }
598             }
599             elsif( $sib->class eq 'PPI::Token::Word' && $sib->content eq 'finally' )
600             {
601 13         193 $inside_finally++;
602 13 50       44 if( scalar( @$buff ) )
603             {
604 13         33 push( @$nodes_to_replace, @$buff );
605 13         27 $buff = [];
606             }
607 13         31 push( @$nodes_to_replace, $sib );
608             }
609             elsif( $inside_finally )
610             {
611             ## $self->_message( 3, "\tWorking on a finally block." );
612             ## We could ignore it, but it is best to let the developer know in case he/she counts on it somehow
613 27 50 66     210 if( $sib->class eq 'PPI::Structure::List' )
    100          
    100          
614             {
615 0         0 die( sprintf( "the finally block does not accept any list parameters at line %d\n", $sib->line_number ) );
616             }
617             elsif( $sib->class eq 'PPI::Structure::Block' )
618             {
619 13         88 $temp->{block} = $sib;
620 13 50       41 if( scalar( @$fin_block_ref ) )
    100          
621             {
622 0         0 die( sprintf( "There can only be one finally block at line %d\n", $sib->line_number ) );
623             }
624             elsif( scalar( @$catch_def ) )
625             {
626 7         21 $catch_def->[-1]->{close_curly_nl} = $nl_counter;
627             }
628             else
629             {
630 6         24 $try_block_ref->[-1]->{close_curly_nl} = $nl_counter;
631             }
632 13         24 $nl_counter = 0;
633 13         23 push( @$fin_block_ref, $temp );
634 13         22 $temp = {};
635 13         29 $inside_finally = 0;
636 13         22 push( @$nodes_to_replace, $sib );
637             }
638             elsif( $sib->class eq 'PPI::Token::Whitespace' && $sib->content =~ /[\015\012]+/ )
639             {
640             ## $self->_messagef( 4, "\tFinally -> Found open new line at line %d", $sib->line_number );
641 1         30 $temp->{open_curly_nl}++;
642 1         2 push( @$nodes_to_replace, $sib );
643             }
644             else
645             {
646 13         235 push( @$nodes_to_replace, $sib );
647             }
648             }
649             # Check for new lines after closing blocks. The ones before, we can account for them in each section above
650             # We could have } catch {
651             # or
652             # }
653             # catch {
654             # etc.
655             # This could also be new lines following the last catch block
656             elsif( $sib->class eq 'PPI::Token::Whitespace' && $sib->content =~ /[\015\012]+/ )
657             {
658             # $self->_messagef( 4, "Between -> Found closing new line at line %d", $sib->line_number );
659 189         3531 $nl_counter++;
660 189         408 push( @$buff, $sib );
661             }
662             else
663             {
664 353         4585 push( @$buff, $sib );
665             }
666 1340         3109 $prev_sib = $sib;
667             }
668            
669 115 100       3541 my $has_catch_clause = scalar( @$catch_def ) > 0 ? 1 : 0;
670            
671             # Prepare the finally block, if any, and add it below at the appropriate place
672 115         223 my $fin_block = '';
673 115 100       295 if( scalar( @$fin_block_ref ) )
674             {
675 13         47 my $fin_def = $fin_block_ref->[0];
676 13         79 $self->_process_caller( finally => $fin_def->{block} );
677             ## my $finally_block = $fin_def->{block}->content;
678 13         153 my $finally_block = $self->_serialize( $fin_def->{block} );
679 13         157 $finally_block =~ s/^\{[[:blank:]]*|[[:blank:]]*\}$//gs;
680 13         45 $fin_block = <
681             CORE::local \$Nice::Try::FINALLY = Nice\::Try\::ScopeGuard->_new(sub __FINALLY_OPEN_NL__{ __BLOCK_PLACEHOLDER__ __FINALLY__CLOSE_NL__}, [\@_], \$Nice::Try::CATCH_DIED);
682             EOT
683 13 50       75 $fin_block =~ s/\n/ /gs unless( $self->{debug_code} );
684 13         53 $fin_block =~ s/__BLOCK_PLACEHOLDER__/$finally_block/gs;
685 13 100       45 if( $fin_def->{open_curly_nl} )
686             {
687 1         5 $fin_block =~ s/__FINALLY_OPEN_NL__/"\n" x $fin_def->{open_curly_nl}/gex;
  1         6  
688             }
689             else
690             {
691 12         50 $fin_block =~ s/__FINALLY_OPEN_NL__//gs;
692             }
693 13 50       36 if( $fin_def->{close_curly_nl} )
694             {
695 0         0 $fin_block =~ s/__FINALLY__CLOSE_NL__/"\n" x $fin_def->{close_curly_nl}/gex;
  0         0  
696             }
697             else
698             {
699 13         52 $fin_block =~ s/__FINALLY__CLOSE_NL__//gs;
700             }
701             }
702              
703             # Found any try block at all?
704 115 100       273 if( scalar( @$try_block_ref ) )
705             {
706             # $self->_message( 3, "Original code to remove is:\n", join( '', @$nodes_to_replace ) );
707             # $self->_message( 3, "Try definition: ", $try_block_ref->[0]->{block}->content );
708             # $self->_messagef( 3, "%d catch clauses found", scalar( @$catch_def ) );
709 113         304 foreach my $c ( @$catch_def )
710             {
711             # $self->_message( 3, "Catch variable assignment: ", $c->{var} );
712             # $self->_message( 3, "Catch block: ", $c->{block} );
713             }
714 113         211 my $try_def = $try_block_ref->[0];
715             # $self->_messagef( 3, "Try new lines before block: %d, after block %d", $try_def->{open_curly_nl}, $try_def->{close_curly_nl} );
716            
717             # Checking for embedded try-catch
718             # $self->_message( 4, "Checking for embedded try-catch in ", $try_def->{block} );
719 113 100       1595 if( my $emb = $self->_parse( $try_def->{block} ) )
720             {
721 3         11 $try_def->{block} = $emb;
722             }
723            
724 113         465 $self->_process_loop_breaks( $try_def->{block} );
725 113         987 $self->_process_caller( try => $try_def->{block} );
726            
727             ## my $try_block = $try_def->{block}->content;
728 113         374 my $try_block = $self->_serialize( $try_def->{block} );
729 113         9260 $try_block =~ s/^\{[[:blank:]]*|[[:blank:]]*\}$//gs;
730            
731 113         529 my $try_sub = <
732             CORE::local \$Nice::Try::THREADED;
733             if( \$INC{'threads.pm'} && !CORE::exists( \$INC{'forks.pm'} ) )
734             {
735             \$Nice::Try::THREADED = threads->tid;
736             }
737             CORE::local \$Nice::Try::WANT;
738             CORE::local ( \$Nice::Try::EXCEPTION, \$Nice::Try::DIED, \$Nice::Try::CATCH_DIED, \@Nice::Try::RETVAL, \@Nice::Try::VOID );
739             CORE::local \$Nice::Try::WANTARRAY = CORE::wantarray;
740             CORE::local \$Nice::Try::TRY = CORE::sub
741             {
742             \@Nice::Try::LAST_VAL = CORE::do __TRY_OPEN_NL__{ __BLOCK_PLACEHOLDER__ };__TRY__CLOSE_NL__
743             CORE::return( \@Nice::Try::LAST_VAL ) if( !CORE::defined( \$Nice::Try::WANTARRAY ) && CORE::scalar( \@Nice::Try::LAST_VAL ) );
744             CORE::return( \$Nice::Try::VOID[0] = \$Nice::Try::SENTINEL );
745             };
746             __FINALLY_BLOCK__ CORE::local \$Nice::Try::HAS_CATCH = $has_catch_clause;
747             EOT
748 113 50 33     857 if( !$self->{is_tied} && !$self->{dont_want} && !$self->{is_overloaded} )
      33        
749             {
750 113         1188 $try_sub .= <
751             CORE::local \$Nice::Try::NOOP = sub
752             {
753             my \$ref = CORE::shift( \@_ );
754             CORE::return(sub{ CORE::return( \$ref ) });
755             };
756             if( CORE::defined( \$Nice::Try::WANTARRAY ) && !\$Nice::Try::THREADED && !( !CORE::length( [CORE::caller]->[1] ) && [CORE::caller(1)]->[3] eq '(eval)' ) )
757             {
758             CORE::eval "\\\$Nice::Try::WANT = Want::want( 'LIST' )
759             ? 'LIST'
760             : Want::want( 'HASH' )
761             ? 'HASH'
762             : Want::want( 'ARRAY' )
763             ? 'ARRAY'
764             : Want::want( 'OBJECT' )
765             ? 'OBJECT'
766             : Want::want( 'CODE' )
767             ? 'CODE'
768             : Want::want( 'REFSCALAR' )
769             ? 'REFSCALAR'
770             : Want::want( 'BOOLEAN' )
771             ? 'BOOLEAN'
772             : Want::want( 'GLOB' )
773             ? 'GLOB'
774             : Want::want( 'SCALAR' )
775             ? 'SCALAR'
776             : Want::want( 'VOID' )
777             ? 'VOID'
778             : '';";
779             undef( \$Nice::Try::WANT ) if( \$\@ );
780             }
781             EOT
782             }
783 113         625 $try_sub .= <
784             {
785             CORE::local \$\@;
786             CORE::eval
787             {
788             if( CORE::defined( \$Nice::Try::WANT ) && CORE::length( \$Nice::Try::WANT ) )
789             {
790             if( \$Nice::Try::WANT eq 'OBJECT' )
791             {
792             \$Nice::Try::RETVAL[0] = Nice::Try::ObjectContext->new( &\$Nice::Try::TRY )->callback();
793             }
794             elsif( \$Nice::Try::WANT eq 'CODE' )
795             {
796             \$Nice::Try::RETVAL[0] = \$Nice::Try::NOOP->( &\$Nice::Try::TRY )->();
797             }
798             elsif( \$Nice::Try::WANT eq 'HASH' )
799             {
800             \@Nice::Try::RETVAL = \%{ &\$Nice::Try::TRY };
801             }
802             elsif( \$Nice::Try::WANT eq 'ARRAY' )
803             {
804             \@Nice::Try::RETVAL = \@{ &\$Nice::Try::TRY };
805             }
806             elsif( \$Nice::Try::WANT eq 'REFSCALAR' )
807             {
808             \$Nice::Try::RETVAL[0] = \${&\$Nice::Try::TRY};
809             }
810             elsif( \$Nice::Try::WANT eq 'GLOB' )
811             {
812             \$Nice::Try::RETVAL[0] = \*{ &\$Nice::Try::TRY };
813             }
814             elsif( \$Nice::Try::WANT eq 'LIST' )
815             {
816             \@Nice::Try::RETVAL = &\$Nice::Try::TRY;
817             }
818             elsif( \$Nice::Try::WANT eq 'BOOLEAN' )
819             {
820             \$Nice::Try::RETVAL[0] = &\$Nice::Try::TRY ? 1 : 0;
821             \$Nice::Try::RETVAL[0] = \$Nice::Try::VOID[0] if( scalar( \@Nice::Try::VOID ) );
822             }
823             elsif( \$Nice::Try::WANT eq 'VOID' )
824             {
825             \$Nice::Try::VOID[0] = &\$Nice::Try::TRY;
826             }
827             elsif( \$Nice::Try::WANT eq 'SCALAR' )
828             {
829             \$Nice::Try::RETVAL[0] = &\$Nice::Try::TRY;
830             }
831             }
832             else
833             {
834             if( \$Nice::Try::WANTARRAY )
835             {
836             \@Nice::Try::RETVAL = &\$Nice::Try::TRY;
837             }
838             elsif( defined( \$Nice::Try::WANTARRAY ) )
839             {
840             \$Nice::Try::RETVAL[0] = &\$Nice::Try::TRY;
841             }
842             else
843             {
844             &\$Nice::Try::TRY;
845             \$Nice::Try::RETVAL[0] = \$Nice::Try::LAST_VAL if( CORE::defined( \$Nice::Try::LAST_VAL ) );
846             }
847             }
848             };
849             \$Nice::Try::DIED = CORE::length( \$\@ ) ? 1 : 0;
850             \$\@ =~ s/[\\015\\012]+\$//g unless( Scalar::Util::blessed( \$\@ ) );
851             \$Nice::Try::EXCEPTION = \$\@;
852             };
853              
854             EOT
855 113 50       3993 $try_sub =~ s/\n/ /gs unless( $self->{debug_code} );
856 113         1105 $try_sub =~ s/__BLOCK_PLACEHOLDER__/$try_block/gs;
857 113 100       386 if( $try_def->{open_curly_nl} )
858             {
859 68         310 $try_sub =~ s/__TRY_OPEN_NL__/"\n" x $try_def->{open_curly_nl}/gex;
  68         572  
860             }
861             else
862             {
863 45         453 $try_sub =~ s/__TRY_OPEN_NL__//gs;
864             }
865 113 100       363 if( $try_def->{close_curly_nl} )
866             {
867 103         530 $try_sub =~ s/__TRY__CLOSE_NL__/"\n" x $try_def->{close_curly_nl}/gex;
  103         722  
868             }
869             else
870             {
871 10         80 $try_sub =~ s/__TRY__CLOSE_NL__//gs;
872             }
873            
874             # Add the final block if there is no catch block, otherwise the final block comes at the end below
875 113 100       323 if( !$has_catch_clause )
876             {
877 8         89 $try_sub =~ s/__FINALLY_BLOCK__/$fin_block/gs;
878             }
879             # If it should not be here, remove the placeholder
880             else
881             {
882 105         841 $try_sub =~ s/__FINALLY_BLOCK__//gs;
883             }
884 113         531 push( @$repl, $try_sub );
885             }
886             else
887             {
888             # $self->_message( 3, "** No try block found!!" );
889 2         10 next;
890             }
891            
892 113         207 my $if_start = <
893             if( \$Nice::Try::DIED )
894             {
895             if( \$Nice::Try::HAS_CATCH )
896             {
897             EOT
898 113 50       584 $if_start =~ s/\n/ /gs unless( $self->{debug_code} );
899 113         270 push( @$catch_repl, $if_start );
900 113 100       296 if( scalar( @$catch_def ) )
901             {
902             # $self->_messagef( 3, "Found %d catch blocks", scalar( @$catch_def ) );
903 105         175 my $total_catch = scalar( @$catch_def );
904             # To count how many times we have else's – obviously we should not have more than 1
905 105         176 my $else = 0;
906 105         356 for( my $i = 0; $i < $total_catch; $i++ )
907             {
908 129         238 my $cdef = $catch_def->[$i];
909             # $self->_messagef( 3, "Catch No ${i} new lines before block: %d, after block %d", $cdef->{open_curly_nl}, $cdef->{close_curly_nl} );
910             # Checking for embedded try-catch
911 129 100       417 if( my $emb = $self->_parse( $cdef->{block} ) )
912             {
913 1         3 $cdef->{block} = $emb;
914             }
915            
916 129 100       418 if( $cdef->{var} )
917             {
918 96         360 $cdef->{var}->prune( 'PPI::Token::Comment' );
919 96         35439 $cdef->{var}->prune( 'PPI::Token::Pod' );
920 96         32535 $self->_messagef( 3, "Catch assignment is: '%s'", $cdef->{var}->content );
921             # my $str = $cdef->{var}->content;
922 96         274 my $str = $self->_serialize( $cdef->{var} );
923 96         823 $str =~ s/^\([[:blank:]\h\v]*|[[:blank:]]*\)$//g;
924             # My::Exception $e
925 96 100       707 if( $str =~ /^(\S+)[[:blank:]\h\v]+(\$\S+)$/ )
    100          
    100          
    100          
    100          
926             {
927 15         84 @$cdef{qw( class var )} = ( $1, $2 );
928             }
929             elsif( $str =~ /^(\S+)[[:blank:]\h\v]+(\$\S+)[[:blank:]\h\v]+where[[:blank:]\h\v]+\{(.*?)\}$/ )
930             {
931 4         34 @$cdef{qw( class var where )} = ( $1, $2, $3 );
932             }
933             elsif( $str =~ /^(\$\S+)[[:blank:]\h\v]+where[[:blank:]\h\v]+\{(.*?)\}$/ )
934             {
935 1         7 @$cdef{qw( var where )} = ( $1, $2 );
936             }
937             elsif( $str =~ /^(\$\S+)[[:blank:]\h\v]+isa[[:blank:]\h\v]+(\S+)(?:[[:blank:]\h\v]+where[[:blank:]\h\v]+\{(.*?)\})?$/ )
938             {
939 9         61 @$cdef{qw( var class where )} = ( $1, $2, $3 );
940             }
941             elsif( $str =~ /^(?\$\S+)[[:blank:]\h\v]+isa[[:blank:]\h\v]*\([[:blank:]\h\v]*(?["'])?(?[^[:blank:]\h\v\'\"\)]+)\k{quote}[[:blank:]\h\v]*\)(?:[[:blank:]\h\v]+where[[:blank:]\h\v]+\{(?.*?)\})?$/ )
942             {
943 24     24   12611 @$cdef{qw( var class where )} = ( $+{var}, $+{class}, $+{where} );
  24         9840  
  24         41420  
  2         42  
944             }
945             else
946             {
947 65         153 $cdef->{var} = $str;
948             }
949             }
950             else
951             {
952             # $self->_message( 3, "No Catch assignment found" );
953             }
954            
955 129 50       453 if( $cdef->{block} )
956             {
957             # $self->_messagef( 3, "Catch block is:\n%s", $cdef->{block}->content );
958             }
959             else
960             {
961             # $self->_message( 3, "No catch block found!" );
962 0         0 next;
963             }
964 129         194 my $cond;
965 129 100       307 if( $i == 0 )
    100          
966             {
967 105         204 $cond = 'if';
968             }
969             elsif( $i == ( $total_catch - 1 ) )
970             {
971             $cond = $total_catch == 1
972             ? 'if'
973             : $cdef->{class}
974 11 100       35 ? 'elsif'
    50          
975             : 'else';
976             }
977             else
978             {
979 13         25 $cond = 'elsif';
980             }
981             # $self->_message( 3, "\$i = $i, \$total_catch = $total_catch and cond = '$cond'" );
982             # my $block = $cdef->{block}->content;
983 129         382 $self->_process_loop_breaks( $cdef->{block} );
984 129         1763 $self->_process_caller( catch => $cdef->{block} );
985 129         367 my $block = $self->_serialize( $cdef->{block} );
986 129         3139 $block =~ s/^\{[[:blank:]]*|[[:blank:]]*\}$//gs;
987 129         299 my $catch_section = '';
988 129         428 my $catch_code = <
989             CORE::local \$Nice::Try::CATCH = CORE::sub
990             {
991             \@Nice::Try::LAST_VAL = CORE::do __CATCH_OPEN_NL__{ __BLOCK_PLACEHOLDER__ }; __CATCH__CLOSE_NL__
992             CORE::return( \@Nice::Try::LAST_VAL ) if( !CORE::defined( \$Nice::Try::WANTARRAY ) && CORE::scalar( \@Nice::Try::LAST_VAL ) );
993             CORE::return \$Nice::Try::SENTINEL;
994             };
995            
996             eval
997             {
998             local \$\@ = \$Nice::Try::EXCEPTION;
999             if( CORE::defined( \$Nice::Try::WANT ) && CORE::length( \$Nice::Try::WANT ) )
1000             {
1001             if( \$Nice::Try::WANT eq 'OBJECT' )
1002             {
1003             \$Nice::Try::RETVAL[0] = Nice::Try::ObjectContext->new( \&\$Nice::Try::CATCH )->callback();
1004             }
1005             elsif( \$Nice::Try::WANT eq 'CODE' )
1006             {
1007             \$Nice::Try::RETVAL[0] = \$Nice::Try::NOOP->( \&\$Nice::Try::CATCH )->();
1008             }
1009             elsif( \$Nice::Try::WANT eq 'HASH' )
1010             {
1011             \@Nice::Try::RETVAL = \%{ \&\$Nice::Try::CATCH };
1012             }
1013             elsif( \$Nice::Try::WANT eq 'ARRAY' )
1014             {
1015             \@Nice::Try::RETVAL = \@{ \&\$Nice::Try::CATCH };
1016             }
1017             elsif( \$Nice::Try::WANT eq 'REFSCALAR' )
1018             {
1019             \$Nice::Try::RETVAL[0] = \${\&\$Nice::Try::CATCH};
1020             }
1021             elsif( \$Nice::Try::WANT eq 'GLOB' )
1022             {
1023             \$Nice::Try::RETVAL[0] = \*{ \&\$Nice::Try::CATCH };
1024             }
1025             elsif( \$Nice::Try::WANT eq 'LIST' )
1026             {
1027             \@Nice::Try::RETVAL = \&\$Nice::Try::CATCH;
1028             }
1029             elsif( \$Nice::Try::WANT eq 'BOOLEAN' )
1030             {
1031             my \$this = \&\$Nice::Try::CATCH ? 1 : 0;
1032             \$Nice::Try::RETVAL[0] = \$Nice::Try::VOID[0] if( scalar( \@Nice::Try::VOID ) );
1033             }
1034             elsif( \$Nice::Try::WANT eq 'VOID' )
1035             {
1036             \$Nice::Try::VOID[0] = \&\$Nice::Try::CATCH;
1037             }
1038             elsif( \$Nice::Try::WANT eq 'SCALAR' )
1039             {
1040             \$Nice::Try::RETVAL[0] = \&\$Nice::Try::CATCH;
1041             }
1042             }
1043             else
1044             {
1045             if( \$Nice::Try::WANTARRAY )
1046             {
1047             \@Nice::Try::RETVAL = \&\$Nice::Try::CATCH;
1048             }
1049             elsif( defined( \$Nice::Try::WANTARRAY ) )
1050             {
1051             \$Nice::Try::RETVAL[0] = \&\$Nice::Try::CATCH;
1052             }
1053             else
1054             {
1055             \&\$Nice::Try::CATCH;
1056             }
1057             }
1058             };
1059             \$Nice::Try::CATCH_DIED = \$\@ if( \$\@ );
1060             EOT
1061 129 100       367 if( $cdef->{var} )
1062             {
1063 96         177 my $ex_var = $cdef->{var};
1064 96 100 100     427 if( $cdef->{class} && $cdef->{where} )
    100          
    100          
1065             {
1066 12         25 my $ex_class = $cdef->{class};
1067 12         37 my $eval = "q{CORE::local \$_ = \$Nice::Try::EXCEPTION; my $ex_var = \$Nice::Try::EXCEPTION; CORE::local \$\@ = \$Nice::Try::EXCEPTION; $cdef->{where}}";
1068 12         110 $catch_section = <
1069             ${cond}( Scalar::Util::blessed( \$Nice::Try::EXCEPTION ) && \$Nice::Try::EXCEPTION->isa( '$ex_class' ) && CORE::eval( $eval ) )
1070             {
1071             CORE::local \$\@ = \$Nice::Try::EXCEPTION;
1072             my $ex_var = \$Nice::Try::EXCEPTION;
1073             $catch_code
1074             }
1075             EOT
1076             }
1077             elsif( $cdef->{class} )
1078             {
1079 18         33 my $ex_class = $cdef->{class};
1080             # Tilmann Haeberle (TH) 2021-03-25: Fix: properly test for exception class inheritance via ->isa
1081 18         190 $catch_section = <
1082             ${cond}( Scalar::Util::blessed( \$Nice::Try::EXCEPTION ) && \$Nice::Try::EXCEPTION->isa( '$ex_class' ) )
1083             {
1084             CORE::local \$\@ = \$Nice::Try::EXCEPTION;
1085             my $ex_var = \$Nice::Try::EXCEPTION;
1086             $catch_code
1087             }
1088             EOT
1089             }
1090             elsif( $cdef->{where} )
1091             {
1092 1         5 my $eval = "q{CORE::local \$_ = \$Nice::Try::EXCEPTION; my $ex_var = \$Nice::Try::EXCEPTION; CORE::local \$\@ = \$Nice::Try::EXCEPTION; $cdef->{where}}";
1093 1         12 $catch_section = <
1094             ${cond}( CORE::eval( $eval ) )
1095             {
1096             CORE::local \$\@ = \$Nice::Try::EXCEPTION;
1097             my $ex_var = \$Nice::Try::EXCEPTION;
1098             $catch_code
1099             }
1100             EOT
1101             }
1102             # No class, just variable assignment like $e or something
1103             else
1104             {
1105             # $self->_message( 3, "Called here for fallback for element No $i" );
1106 65 50       211 if( ++$else > 1 )
1107             {
1108             # CORE::warn( "Cannot have more than one falllback catch clause for block: ", $cdef->{block}->content, "\n" ) if( warnings::enabled );
1109 0 0       0 CORE::warn( "Cannot have more than one falllback catch clause for block: ", $self->_serialize( $cdef->{block} ), "\n" ) if( warnings::enabled );
1110             # Skip, not die. Not fatal, just ignored
1111 0         0 next;
1112             }
1113 65 100 66     243 $cond = "${cond}( 1 )" if( $cond eq 'if' || $cond eq 'elsif' );
1114             # push( @$catch_repl, <
1115 65         663 $catch_section = <
1116             ${cond}
1117             {
1118             CORE::local \$\@ = \$Nice::Try::EXCEPTION;
1119             my $ex_var = \$Nice::Try::EXCEPTION;
1120             $catch_code
1121             }
1122             EOT
1123             }
1124             }
1125             # No variable assignment like $e
1126             else
1127             {
1128 33 50 33     197 $cond = "${cond}( 1 )" if( $cond eq 'if' || $cond eq 'elsif' );
1129 33         273 $catch_section = <
1130             ${cond}
1131             {
1132             CORE::local \$\@ = \$Nice::Try::EXCEPTION;
1133             $catch_code
1134             }
1135             EOT
1136             }
1137 129 50       3397 $catch_section =~ s/\n/ /gs unless( $self->{debug_code} );
1138 129         987 $catch_section =~ s/__BLOCK_PLACEHOLDER__/$block/gs;
1139 129 100       392 if( $cdef->{open_curly_nl} )
1140             {
1141 87         400 $catch_section =~ s/__CATCH_OPEN_NL__/"\n" x $cdef->{open_curly_nl}/gex;
  87         607  
1142             }
1143             else
1144             {
1145 42         274 $catch_section =~ s/__CATCH_OPEN_NL__//gs;
1146             }
1147 129 100       383 if( $cdef->{close_curly_nl} )
1148             {
1149 27         106 $catch_section =~ s/__CATCH__CLOSE_NL__/"\n" x $cdef->{close_curly_nl}/gex;
  27         166  
1150             }
1151             else
1152             {
1153 102         699 $catch_section =~ s/__CATCH__CLOSE_NL__//gs;
1154             }
1155 129         627 push( @$catch_repl, $catch_section );
1156             }
1157             # End catch loop
1158             # Tilmann Haeberle (TH) 2021-03-25: Fix: put an else at the end to avoid 'fall_through' issue unless an else exists already
1159 105         189 my $if_end;
1160 105 100       233 if( $else )
1161             {
1162 65         116 $if_end = <
1163             }
1164             EOT
1165             }
1166             else
1167             {
1168 40         76 $if_end = <
1169             else
1170             {
1171             die( \$Nice::Try::EXCEPTION );
1172             }
1173             }
1174             EOT
1175             }
1176 105 50       491 $if_end =~ s/\n/ /g unless( $self->{debug_code} );
1177 105         270 push( @$catch_repl, $if_end );
1178             }
1179             # No catch clause
1180             else
1181             {
1182             # If the try-catch block is called inside an eval, propagate the exception
1183             # Otherwise, we just make the $@ available
1184 8         32 my $catch_else = <
1185             }
1186             else
1187             {
1188             if( CORE::defined( (CORE::caller(0))[3] ) && (CORE::caller(0))[3] eq '(eval)' )
1189             {
1190             CORE::die( \$Nice::Try::EXCEPTION );
1191             }
1192             else
1193             {
1194             \$\@ = \$Nice::Try::EXCEPTION;
1195             }
1196             }
1197             EOT
1198 8 50       62 $catch_else =~ s/\n/ /g unless( $self->{debug_code} );
1199 8         23 push( @$catch_repl, $catch_else );
1200             }
1201            
1202             # Add
1203 113 50       2623 my $catch_res = scalar( @$catch_repl ) ? join( '', @$catch_repl ) : '';
1204 113 50       374 push( @$repl, $catch_res ) if( $catch_res );
1205             # Closing the If DIED condition
1206 113         246 push( @$repl, "\};" );
1207              
1208             # If there is a catch clause, we put the final block here, if any
1209 113 100 100     501 if( $has_catch_clause && CORE::length( $fin_block ) )
1210             {
1211 7         12 push( @$repl, $fin_block );
1212             }
1213            
1214             # After the finally block has been registered, we will die if catch had a fatal error
1215 113         191 my $catch_dies = <
1216             if( defined( \$Nice::Try::CATCH_DIED ) )
1217             {
1218             die( \$Nice::Try::CATCH_DIED );
1219             }
1220             EOT
1221 113 50       578 $catch_dies =~ s/\n/ /gs unless( $self->{debug_code} );
1222 113         262 push( @$repl, $catch_dies );
1223            
1224 113         407 my $last_return_block = <
1225             if( ( CORE::defined( \$Nice::Try::WANTARRAY ) || ( defined( \$Nice::Try::BREAK ) && \$Nice::Try::BREAK eq 'return' ) ) and
1226             (
1227             !Scalar::Util::blessed( \$Nice::Try::RETVAL[0] ) or
1228             ( Scalar::Util::blessed( \$Nice::Try::RETVAL[0] ) && !\$Nice::Try::RETVAL[0]->isa( 'Nice::Try::SENTINEL' ) )
1229             ) )
1230             {
1231             if( !CORE::defined( \$Nice::Try::BREAK ) || \$Nice::Try::BREAK eq 'return' )
1232             {
1233             if( CORE::defined( \$Nice::Try::WANT ) && CORE::length( \$Nice::Try::WANT ) )
1234             {
1235             if( \$Nice::Try::WANT eq 'LIST' )
1236             {
1237             CORE::return( \@Nice::Try::RETVAL );
1238             }
1239             elsif( \$Nice::Try::WANT eq 'VOID' )
1240             {
1241             if( CORE::defined( \$Nice::Try::RETVAL[0] ) && \$Nice::Try::RETVAL[0] eq '__NEXT__' )
1242             {
1243             \$Nice::Try::BREAK = 'next';
1244             }
1245             elsif( CORE::defined( \$Nice::Try::RETVAL[0] ) && \$Nice::Try::RETVAL[0] eq '__LAST__' )
1246             {
1247             \$Nice::Try::BREAK = 'last';
1248             }
1249             elsif( CORE::defined( \$Nice::Try::RETVAL[0] ) && \$Nice::Try::RETVAL[0] eq '__REDO__' )
1250             {
1251             \$Nice::Try::BREAK = 'redo';
1252             }
1253             elsif( defined( \$Nice::Try::BREAK ) && \$Nice::Try::BREAK eq 'return' )
1254             {
1255             CORE::return( \$Nice::Try::RETVAL[0] );
1256             }
1257             }
1258             elsif( \$Nice::Try::WANT eq 'OBJECT' )
1259             {
1260             CORE::return( \$Nice::Try::RETVAL[0] );
1261             }
1262             elsif( \$Nice::Try::WANT eq 'REFSCALAR' )
1263             {
1264             CORE::return( \\\$Nice::Try::RETVAL[0] );
1265             }
1266             elsif( \$Nice::Try::WANT eq 'SCALAR' )
1267             {
1268             CORE::return( \$Nice::Try::RETVAL[0] );
1269             }
1270             elsif( \$Nice::Try::WANT eq 'BOOLEAN' )
1271             {
1272             CORE::return( \$Nice::Try::RETVAL[0] );
1273             }
1274             elsif( \$Nice::Try::WANT eq 'CODE' )
1275             {
1276             CORE::return( \$Nice::Try::RETVAL[0] );
1277             }
1278             elsif( \$Nice::Try::WANT eq 'HASH' )
1279             {
1280             CORE::return( { \@Nice::Try::RETVAL } );
1281             }
1282             elsif( \$Nice::Try::WANT eq 'ARRAY' )
1283             {
1284             CORE::return( \\\@Nice::Try::RETVAL );
1285             }
1286             elsif( \$Nice::Try::WANT eq 'GLOB' )
1287             {
1288             CORE::return( \$Nice::Try::RETVAL[0] );
1289             }
1290             }
1291             else
1292             {
1293             CORE::return( \$Nice::Try::WANTARRAY ? \@Nice::Try::RETVAL : \$Nice::Try::RETVAL[0] );
1294             }
1295             }
1296             }
1297             EOT
1298 113 50       2458 $last_return_block =~ s/\n/ /gs unless( $self->{debug_code} );
1299 113         420 push( @$repl, $last_return_block );
1300 113         2323 my $try_catch_code = join( '', @$repl );
1301             # my $token = PPI::Token->new( "; \{ $try_catch_code \}" ) || die( "Unable to create token" );
1302             # XXX 2021-05-11 (Jacques): Need to remove blocks so that next or last statements can be effective.
1303 113         281 my $envelop = <
1304             ; CORE::local( \$Nice::Try::BREAK, \@Nice::Try::LAST_VAL );
1305             \{
1306             __TRY_CATCH_CODE__
1307             \}
1308             if( CORE::defined( \$Nice::Try::BREAK ) )
1309             {
1310             if( \$Nice::Try::BREAK eq 'next' )
1311             {
1312             CORE::next;
1313             }
1314             elsif( \$Nice::Try::BREAK eq 'last' )
1315             {
1316             CORE::last;
1317             }
1318             elsif( \$Nice::Try::BREAK eq 'redo' )
1319             {
1320             CORE::redo;
1321             }
1322             }
1323             no warnings 'void';
1324             CORE::scalar( \@Nice::Try::LAST_VAL ) > 1 ? \@Nice::Try::LAST_VAL : \$Nice::Try::LAST_VAL[0];
1325             EOT
1326 113 50       1117 $envelop =~ s/\n/ /gs unless( $self->{debug_code} );
1327 113         2049 $envelop =~ s/__TRY_CATCH_CODE__/$try_catch_code/;
1328 113   50     623 my $token = PPI::Token->new( $envelop ) || die( "Unable to create token" );
1329 113         4470 $token->set_class( 'Structure' );
1330             # $self->_messagef( 3, "Token is '$token' and of class '%s' and inherit from PPI::Token? %s", $token->class, ($token->isa( 'PPI::Token' ) ? 'yes' : 'no' ) );
1331 113   50     2283 my $struct = PPI::Structure->new( $token ) || die( "Unable to create PPI::Structure element" );
1332             # $self->_message( 3, "Resulting try-catch block is:\n'$token'" );
1333 113         4300 my $orig_try_catch_block = join( '', @$nodes_to_replace );
1334             # $self->_message( 3, "Original try-catch block is:\n'$orig_try_catch_block'" );
1335             # $self->_messagef( 3, "Element before our try-catch block is of class %s with value '%s'", $element_before_try->class, $element_before_try->content );
1336 113         33466 my $rc;
1337 113 50       417 if( !( $rc = $element_before_try->insert_after( $token ) ) )
1338             {
1339             # $self->_message( 3, "Return code is defined? ", CORE::defined( $rc ) ? 'yes' : 'no', " and is it a PPI::Element object? ", $token->isa( 'PPI::Element' ) ? 'yes' : 'no' );
1340 0         0 $self->_error( "Failed to add replacement code of class '", $token->class, "' after '$element_before_try'" );
1341 0         0 next;
1342             }
1343 113 0       6745 $self->_message( 3, "Return code is defined? ", defined( $rc ) ? "yes" : "no" ) if( $self->{debug} >= 3 );
    50          
1344            
1345 113         360 for( my $k = 0; $k < scalar( @$nodes_to_replace ); $k++ )
1346             {
1347 1293         80783 my $e = $nodes_to_replace->[$k];
1348             ## $self->_messagef( 4, "[$k] Removing node: $e" );
1349 1293 50       2756 $e->delete || warn( "Could not remove node No $k: '$e'\n" );
1350             }
1351             }
1352             # End foreach catch found
1353            
1354             # $self->_message( 3, "\n\nResulting code is\n", $elem->content );
1355 25         8384 return( $elem );
1356             }
1357              
1358             # .Element: [11] class PPI::Token::Word, value caller
1359             # .Element: [11] class PPI::Structure::List, value (1)
1360             #
1361             # ..Element: [12] class PPI::Token::Word, value caller
1362             # ..Element: [12] class PPI::Token::Structure, value ;
1363              
1364             sub _process_caller
1365             {
1366 1428     1428   2150 my $self = shift( @_ );
1367 1428         2290 my $where = shift( @_ );
1368 1428   50     3557 my $elem = shift( @_ ) || return( '' );
1369 24     24   233 no warnings 'uninitialized';
  24         68  
  24         6133  
1370 1428 100       2897 return( $elem ) if( !$elem->children );
1371 1419         7512 foreach my $e ( $elem->elements )
1372             {
1373 7077   50     20010 my $content = $e->content // '';
1374             # $self->_messagef( 6, "Checking element: [%d] class %s with %d children and value '%s'\n", $e->line_number, $e->class, ( $e->can('elements') ? scalar( $e->elements ) : 0 ), $content );
1375 7077         75728 my $class = $e->class;
1376 7077 100 100     24035 if( $class eq 'PPI::Token::Word' && $content =~ /^(?:CORE\::)?(?:GLOBAL\::)?caller$/ )
1377             {
1378             # $self->_message( 4, "Found caller, replacing with ", 'Nice::Try::caller_' . $where );
1379 5         23 $e->set_content( 'Nice::Try::caller_' . $where );
1380             }
1381            
1382 7077 100 100     19568 if( $e->can('elements') && $e->elements )
1383             {
1384 1173         9642 $self->_process_caller( $where => $e );
1385             }
1386             }
1387             # $self->_message( 5, "Element now is: '$elem'" );
1388             # $self->_browse( $elem );
1389 1419         2952 return( $elem );
1390             }
1391              
1392             sub _process_loop_breaks
1393             {
1394 1223     1223   2213 my $self = shift( @_ );
1395 1223   50     3182 my $elem = shift( @_ ) || return( '' );
1396 24     24   214 no warnings 'uninitialized';
  24         58  
  24         23220  
1397 1223 100       2844 return( $elem ) if( !$elem->children );
1398 1215 50       6824 $self->_message( 5, "Checking ", scalar( $elem->elements ), " elements for '$elem'" ) if( $self->{debug} >= 5 );
1399 1215         2464 foreach my $e ( $elem->elements )
1400             {
1401 5998   50     19745 my $content = $e->content // '';
1402 5998 0       67475 $self->_messagef( 6, "Checking element: [%d] class %s with %d children and value '%s'\n", $e->line_number, $e->class, ( $e->can('elements') ? scalar( $e->elements ) : 0 ), $content ) if( $self->{debug} >= 6 );
    50          
1403 5998         10448 my $class = $e->class;
1404             # We found a for, foreach or while loops and we skip, because if there are any break words (next, last, redo) inside, it is not our problem.
1405 5998 50 66     35709 if( $class eq 'PPI::Structure::For' ||
    50 66        
    100 33        
      66        
1406             ( $class eq 'PPI::Statement::Compound' &&
1407             CORE::defined( $e->first_element->content ) &&
1408             $e->first_element->content =~ /^(for|foreach|while)$/ ) )
1409             {
1410             # $self->_message( 6, "Skipping it. Its first word was '", $e->first_element->content, "'" );
1411 0         0 next;
1412             }
1413             elsif( $class eq 'PPI::Token::Word' && $content =~ /^(?:CORE\::)?(?:GLOBAL\::)?(next|last|redo)$/ )
1414             {
1415 0 0       0 $self->_message( 5, "Found loop keyword '$content'." ) if( $self->{debug} >= 5 );
1416             # $e->set_content( qq{CORE::return( '__} . uc( $1 ) . qq{__' )} );
1417             # $e->set_content( q{$Nice::Try::BREAK='__} . uc( $1 ) . qq{__' ); return;} );
1418 0         0 my $break_code = q{$Nice::Try::BREAK='} . $1 . qq{', return;};
1419 0         0 my $break_doc = PPI::Document->new( \$break_code, readonly => 1 );
1420 0         0 my $new_elem = $break_doc->first_element;
1421             # $self->_browse( $new_elem );
1422 0         0 $new_elem->remove;
1423 0 0   0   0 $self->_message( 5, "New element is object '", sub{ overload::StrVal( $new_elem ) }, "' -> $new_elem" ) if( $self->{debug} >= 5 );
  0         0  
1424             # Not yet implemented as of 2021-05-11 dixit PPI, so we use a hack to make it available anyhow
1425 0         0 $e->replace( $new_elem );
1426 0 0       0 $self->_message( 5, "Loop keyword now replaced with '$e'." ) if( $self->{debug} >= 5 );
1427             }
1428             elsif( $class eq 'PPI::Statement::Break' )
1429             {
1430 82         303 my $words = $e->find( 'PPI::Token::Word' );
1431 82 50       27812 $self->_messagef( 5, "Found %d word elements inside break element.", scalar( @$words ) ) if( $self->{debug} >= 5 );
1432 82 50 50     363 my $word1 = ( scalar( @$words ) ? $words->[0]->content // '' : '' );
1433 82 100 50     480 my $word2 = ( scalar( @$words ) > 1 ? $words->[1]->content // '' : '' );
1434 82 50       256 $self->_message( 5, "Word 1 -> ", $word1 ) if( $self->{debug} >= 5 );
1435 82 50 33     220 $self->_message( 5, "Word 2 -> ", $word2 ) if( $self->{debug} >= 5 && scalar( @$words ) > 1 );
1436             # $self->_browse( $e );
1437             # If we found a break word without a label, i.e. next, last, redo,
1438             # we replace it with a special return statement
1439 82 50 100     823 if( (
      66        
      100        
1440             scalar( @$words ) == 1 ||
1441             ( scalar( @$words ) > 1 && $word2 =~ /^(for|foreach|given|if|unless|until|while)$/ ) ||
1442             $word1 eq 'return'
1443             ) &&
1444             (
1445             $word1 eq 'next' ||
1446             $word1 eq 'last' ||
1447             $word1 eq 'redo' ||
1448             $word1 eq 'return'
1449             ) )
1450             {
1451             # We add our special return value. Notice that we use 'return' and not
1452             # 'CORE::return'. See below why.
1453             # my $break_code = qq{return( '__} . uc( $word1 ) . qq{__' )};
1454 70 100       300 my $break_code = q{$Nice::Try::BREAK='} . $word1 . ( $word1 eq 'return' ? "', $e" : qq{', return} );
1455             # e.g. next if( $i == 2 );
1456             # next and if are both treated as 'word' by PPI
1457 70 100       1755 if( scalar( @$words ) > 1 )
1458             {
1459 10         35 ( my $ct = $e->content ) =~ s/^(next|last|redo)//;
1460 10         775 $break_code .= $ct;
1461             }
1462             else
1463             {
1464 60         100 $break_code .= ';'
1465             }
1466 70 50       188 $self->_message( 5, "Replacing this node with: $break_code" ) if( $self->{debug} >= 5 );
1467            
1468 70         310 my $break_doc = PPI::Document->new( \$break_code, readonly => 1 );
1469 70         142908 my $new_elem = $break_doc->first_element;
1470             # $self->_browse( $new_elem );
1471 70         506 $new_elem->remove;
1472 70 50   0   2943 $self->_message( 5, "New element is object '", sub{ overload::StrVal( $new_elem ) }, "' -> $new_elem" ) if( $self->{debug} >= 5 );
  0         0  
1473             # Not yet implemented as of 2021-05-11 dixit PPI, so we use a hack to make it available anyhow
1474 70 50       172 $self->_message( 5, "Updated element now is '$e' for class '", $e->class, "' and parent class '", $e->parent->class, "'." ) if( $self->{debug} >= 5 );
1475 70         251 $e->replace( $new_elem );
1476             # 2021-05-12 (Jacques): I have to do this workaround, because weirdly enough
1477             # PPI (at least with PPI::Node version 1.270) will refuse to add our element
1478             # if the 'return' word is 'CORE::return' so, we add it without and change it after
1479             # $new_elem->first_element->set_content( 'CORE::return' );
1480             # $self->_message( 5, "return litteral value is: ", $new_elem->first_element->content );
1481             }
1482 82         2688 next;
1483             }
1484            
1485 5916 100 100     19046 if( $e->can('elements') && $e->elements )
1486             {
1487 981         8860 $self->_process_loop_breaks( $e );
1488             }
1489             }
1490             # $self->_message( 5, "Element now is: '", sub{ $elem->content }, "'" );
1491             # $self->_message( 5, "Element now is: '$elem'" );
1492             # $self->_browse( $elem );
1493 1215         2781 return( $elem );
1494             }
1495              
1496             ## Taken from PPI::Document
1497             sub _serialize
1498             {
1499 351     351   580 my $self = shift( @_ );
1500 351   50     1103 my $ppi = shift( @_ ) || return( '' );
1501 24     24   231 no warnings 'uninitialized';
  24         66  
  24         17027  
1502 351         1036 my @tokens = $ppi->tokens;
1503              
1504             # The here-doc content buffer
1505 351         27440 my $heredoc = '';
1506              
1507             # Start the main loop
1508 351         540 my $output = '';
1509 351         1017 foreach my $i ( 0 .. $#tokens ) {
1510 6767         8414 my $Token = $tokens[$i];
1511              
1512             # Handle normal tokens
1513 6767 50       17449 unless ( $Token->isa('PPI::Token::HereDoc') ) {
1514 6767         11358 my $content = $Token->content;
1515              
1516             # Handle the trivial cases
1517 6767 50 33     23562 unless ( $heredoc ne '' and $content =~ /\n/ ) {
1518 6767         8819 $output .= $content;
1519 6767         9755 next;
1520             }
1521              
1522             # We have pending here-doc content that needs to be
1523             # inserted just after the first newline in the content.
1524 0 0       0 if ( $content eq "\n" ) {
1525             # Shortcut the most common case for speed
1526 0         0 $output .= $content . $heredoc;
1527             } else {
1528             # Slower and more general version
1529 0         0 $content =~ s/\n/\n$heredoc/;
1530 0         0 $output .= $content;
1531             }
1532              
1533 0         0 $heredoc = '';
1534 0         0 next;
1535             }
1536              
1537             # This token is a HereDoc.
1538             # First, add the token content as normal, which in this
1539             # case will definitely not contain a newline.
1540 0         0 $output .= $Token->content;
1541              
1542             # Now add all of the here-doc content to the heredoc buffer.
1543 0         0 foreach my $line ( $Token->heredoc ) {
1544 0         0 $heredoc .= $line;
1545             }
1546              
1547 0 0       0 if ( $Token->{_damaged} ) {
1548             # Special Case:
1549             # There are a couple of warning/bug situations
1550             # that can occur when a HereDoc content was read in
1551             # from the end of a file that we silently allow.
1552             #
1553             # When writing back out to the file we have to
1554             # auto-repair these problems if we aren't going back
1555             # on to the end of the file.
1556              
1557             # When calculating $last_line, ignore the final token if
1558             # and only if it has a single newline at the end.
1559 0         0 my $last_index = $#tokens;
1560 0 0       0 if ( $tokens[$last_index]->{content} =~ /^[^\n]*\n$/ ) {
1561 0         0 $last_index--;
1562             }
1563              
1564             # This is a two part test.
1565             # First, are we on the last line of the
1566             # content part of the file
1567             my $last_line = List::Util::none {
1568 0 0   0   0 $tokens[$_] and $tokens[$_]->{content} =~ /\n/
1569 0         0 } (($i + 1) .. $last_index);
1570 0 0       0 if ( ! defined $last_line ) {
1571             # Handles the null list case
1572 0         0 $last_line = 1;
1573             }
1574              
1575             # Secondly, are their any more here-docs after us,
1576             # (with content or a terminator)
1577             my $any_after = List::Util::any {
1578             $tokens[$_]->isa('PPI::Token::HereDoc')
1579             and (
1580 0         0 scalar(@{$tokens[$_]->{_heredoc}})
1581             or
1582             defined $tokens[$_]->{_terminator_line}
1583             )
1584 0 0 0 0   0 } (($i + 1) .. $#tokens);
  0         0  
1585 0 0       0 if ( ! defined $any_after ) {
1586             # Handles the null list case
1587 0         0 $any_after = '';
1588             }
1589              
1590             # We don't need to repair the last here-doc on the
1591             # last line. But we do need to repair anything else.
1592 0 0 0     0 unless ( $last_line and ! $any_after ) {
1593             # Add a terminating string if it didn't have one
1594 0 0       0 unless ( defined $Token->{_terminator_line} ) {
1595 0         0 $Token->{_terminator_line} = $Token->{_terminator};
1596             }
1597              
1598             # Add a trailing newline to the terminating
1599             # string if it didn't have one.
1600 0 0       0 unless ( $Token->{_terminator_line} =~ /\n$/ ) {
1601 0         0 $Token->{_terminator_line} .= "\n";
1602             }
1603             }
1604             }
1605              
1606             # Now add the termination line to the heredoc buffer
1607 0 0       0 if ( defined $Token->{_terminator_line} ) {
1608 0         0 $heredoc .= $Token->{_terminator_line};
1609             }
1610             }
1611              
1612             # End of tokens
1613              
1614 351 50       788 if ( $heredoc ne '' ) {
1615             # If the file doesn't end in a newline, we need to add one
1616             # so that the here-doc content starts on the next line.
1617 0 0       0 unless ( $output =~ /\n$/ ) {
1618 0         0 $output .= "\n";
1619             }
1620              
1621             # Now we add the remaining here-doc content
1622             # to the end of the file.
1623 0         0 $output .= $heredoc;
1624             }
1625              
1626 351         1093 $output;
1627             }
1628              
1629              
1630             {
1631             # NOTE: Nice::Try::ScopeGuard class
1632             package # hide from PAUSE
1633             Nice::Try::ScopeGuard;
1634              
1635             # older versions of perl have an issue with $@ during global destruction
1636 24 50   24   255 use constant UNSTABLE_DOLLARAT => ("$]" < '5.013002') ? 1 : 0;
  24         72  
  24         13178  
1637              
1638             sub _new
1639             {
1640 14     14   15066 my $this = shift( @_ );
1641 14   33     110 return( bless( [ @_ ] => ( ref( $this ) || $this ) ) );
1642             }
1643              
1644             sub DESTROY
1645             {
1646 14     14   854 my( $code, $args, $catch_err ) = @{ $_[0] };
  14         60  
1647             # save the current exception to make it available in the finally sub,
1648             # and to restore it after the eval
1649 14 50       44 my $err = defined( $catch_err ) ? $catch_err : $@;
1650 14         23 local $@ if( UNSTABLE_DOLLARAT );
1651 14 50       38 $@ = $catch_err if( defined( $catch_err ) );
1652             CORE::eval
1653             {
1654 14         23 $@ = $err;
1655 14         40 $code->( @$args );
1656 13         1615 1;
1657             }
1658             or do
1659 14 100       25 {
1660 1 50       26 CORE::warn
1661             "Execution of finally() block $code resulted in an exception, which "
1662             . '*CAN NOT BE PROPAGATED* due to fundamental limitations of Perl. '
1663             . 'Your program will continue as if this event never took place. '
1664             . "Original exception text follows:\n\n"
1665             . (defined $@ ? $@ : '$@ left undefined...')
1666             . "\n"
1667             ;
1668             };
1669             # maybe unnecessary?
1670 14         153 $@ = $err;
1671             }
1672             }
1673              
1674             {
1675             package
1676             Nice::Try::ObjectContext;
1677              
1678             sub new
1679             {
1680 2     2   25138 my $that = shift( @_ );
1681             # print( STDERR "Got here in Nice::Try::ObjectContext->new with args '", join( "', '", @_ ), "'\n" );
1682 2   33     21 return( bless( { val => [@_] } => ( ref( $that ) || $that ) ) );
1683             }
1684              
1685             sub callback
1686             {
1687 2     2   6 my $self = shift( @_ );
1688             # print( STDERR "Got here in Nice::Try::ObjectContext->dummy with args '", join( "', '", @_ ), "'\n" );
1689 2         12 return( $self->{val}->[0] );
1690             }
1691             }
1692              
1693             {
1694             package
1695             PPI::Element;
1696            
1697 24     24   222 no warnings 'redefine';
  24         65  
  24         3950  
1698             sub replace {
1699 70 50   70 1 243 my $self = ref $_[0] ? shift : return undef;
1700             # If our object and the other are not of the same class, PPI refuses to replace
1701             # to avoid damages to perl code
1702             # my $other = _INSTANCE(shift, ref $self) or return undef;
1703 70         111 my $other = shift;
1704             # die "The ->replace method has not yet been implemented";
1705 70         215 $self->parent->__replace_child( $self, $other );
1706 70         2833 1;
1707             }
1708             }
1709              
1710             1;
1711              
1712             # XXX POD
1713             __END__