File Coverage

blib/lib/Acme/ComeFrom.pm
Criterion Covered Total %
statement 25 25 100.0
branch 5 6 83.3
condition n/a
subroutine 5 5 100.0
pod 0 1 0.0
total 35 37 94.5


line stmt bran cond sub pod time code
1             package Acme::ComeFrom;
2             $Acme::ComeFrom::VERSION = '0.11';
3              
4 2     2   55 use 5.005;
  2         9  
  2         84  
5 2     2   95 use strict;
  2         4  
  2         86  
6 2     2   10 use vars qw/$CacheEXPR/;
  2         3  
  2         82  
7 2     2   12673 use Filter::Simple 0.70;
  2         80234  
  2         14  
8              
9             my $Mark = '__COME_FROM';
10             my $count = '0000';
11              
12             FILTER_ONLY code => sub {
13             my ( %subs, %labels, @tokens, @counts );
14             my $source = $_;
15              
16             $_ = $source and return unless $source =~ /comefrom/;
17              
18             while ( $source =~
19             s/\bcomefrom\b(\s*)\(?(&?)?([\w\:]+|[^\;]+)(?:\(\))?\)?/$Mark$count:$1/ )
20             {
21             my $token = $3;
22              
23             push @{ $subs{$token} }, $count++ and next if $2;
24             push @{ $labels{$token} }, $count++ and next if $token =~ /^[\w\:]+$/;
25             push @tokens, $token;
26             push @counts, $count++;
27             }
28              
29             $_ = $source and return unless %subs or %labels or @tokens;
30              
31             my $code = '';
32              
33             if (%subs) {
34             require Hook::LexWrap;
35             $code .= 'require Hook::LexWrap;';
36             }
37              
38             while ( my ( $k, $v ) = each %subs ) {
39             my $chunk = make_chunk($v);
40             $code .= "Hook::LexWrap::wrap($k, post => sub { $chunk });";
41             }
42              
43             if (@tokens) {
44             $source =~ s!(\n\s*)([a-zA-Z_]\w+):!
45             my $label = $2;
46             my $chunk = make_chunk(
47             [ @counts, exists $labels{$label} ? @{$labels{$label}} : ()],
48             $label, \@tokens
49             ) unless substr($label, 0, length($Mark)) eq $Mark;
50              
51             "$1$label:" . ($chunk ? "do {$chunk};" : '');
52             !eg;
53             }
54             else {
55             while ( my ( $k, $v ) = each %labels ) {
56             my $chunk = make_chunk($v);
57             $source =~ s!\Q$k\E:!$k: do {$chunk};!g;
58             }
59             }
60              
61             $_ = ( $code ? "CHECK { $code; 1 };" : '' ) . $source;
62             };
63              
64             sub make_chunk {
65 7     7 0 11 my $pkg = '$' . __PACKAGE__;
66 7         16 my ( $v, $label, $cond ) = @_;
67 7         11 my $chunk = '';
68              
69 7         14 foreach my $iter ( 0 .. $#{$v} ) {
  7         20  
70 9         11 my $fork = ( $iter != $#{$v} );
  9         18  
71              
72 9 100       23 if ( defined $cond->[$iter] ) {
73 6 100       15 my $forktext = ( $fork ? ' or fork' : '' );
74              
75 6         57 $chunk .= "
76             if (\$Acme::ComeFrom::CacheEXPR) {
77             $pkg\::CACHE[$v->[$iter]] = eval q;$cond->[$iter];
78             unless exists $pkg\::CACHE[$v->[$iter]];
79              
80             goto $Mark$v->[$iter] unless
81             ('$label' ne $pkg\::CACHE[$v->[$iter]])$forktext;
82             }
83             else {
84             goto $Mark$v->[$iter] unless
85             ('$label' ne eval q;$cond->[$iter];)$forktext;
86             }
87             ";
88             }
89             else {
90 3 50       14 $chunk .= "goto $Mark$v->[$iter]" . ( $fork ? " unless fork();" : ';' );
91             }
92             }
93              
94 7         85 $chunk =~ s/\n */ /g;
95 7         18 return $chunk;
96             }
97              
98             1;
99              
100             __END__