File Coverage

blib/lib/Acme/Gosub.pm
Criterion Covered Total %
statement 76 81 93.8
branch 21 26 80.7
condition 2 5 40.0
subroutine 10 11 90.9
pod 3 3 100.0
total 112 126 88.8


line stmt bran cond sub pod time code
1             package Acme::Gosub;
2             $Acme::Gosub::VERSION = '0.1.7';
3 2     2   145851 use strict;
  2         26  
  2         69  
4 2     2   14 use warnings;
  2         5  
  2         65  
5 2     2   15 use Carp;
  2         4  
  2         131  
6              
7             # LOAD FILTERING MODULE...
8 2     2   1255 use Filter::Util::Call;
  2         2019  
  2         162  
9              
10             # CATCH ATTEMPTS TO CALL case OUTSIDE THE SCOPE OF ANY switch
11              
12             my $next_label_idx = 0;
13 2     2   31 use vars qw(%ret_labels);
  2         5  
  2         757  
14              
15             $::_S_W_I_T_C_H = sub { croak "case/when statement not in switch/given block" };
16              
17             my $offset;
18             my $fallthrough;
19              
20             sub import
21             {
22 2     2   28 $fallthrough = grep /\bfallthrough\b/, @_;
23 2         9 $offset = (caller)[2]+1;
24 2 50 33     22 filter_add({}) unless @_>1 && $_[1] eq 'noimport';
25 2         58 my $pkg = caller;
26 2         21 1;
27             }
28              
29             sub unimport
30             {
31 0     0   0 filter_del()
32             }
33              
34             sub filter
35             {
36 4     4 1 407 my($self) = @_ ;
37 4         15 local $Acme::Gosub::file = (caller)[1];
38              
39 4         11 my $status = 1;
40 4         93 $status = filter_read(1_000_000);
41 4 50       20 return $status if $status<0;
42 4         22 $_ = filter_blocks($_,$offset);
43 4 100       24 $_ = "# line $offset\n" . $_ if $offset; undef $offset;
  4         8  
44 4         3740 return $status;
45             }
46              
47 2     2   1473 use Text::Balanced ':ALL';
  2         43769  
  2         1902  
48              
49             sub line
50             {
51 3     3 1 15 my ($pretext,$offset) = @_;
52 3   50     27 ($pretext=~tr/\n/\n/)+($offset||0);
53             }
54              
55             my $EOP = qr/\n\n|\Z/;
56             my $CUT = qr/\n=cut.*$EOP/;
57             my $pod_or_DATA = qr/ ^=(?:head[1-4]|item) .*? $CUT
58             | ^=pod .*? $CUT
59             | ^=for .*? $EOP
60             | ^=begin \s* (\S+) .*? \n=end \s* \1 .*? $EOP
61             | ^__(DATA|END)__\n.*
62             /smx;
63              
64             my $casecounter = 1;
65             sub filter_blocks
66             {
67 7     7 1 26 my ($source, $line) = @_;
68 7 100       50 return $source unless $source =~ /gosub|greturn/;
69 1         4 pos $source = 0;
70 1         3 my $text = "";
71 1         5 component: while (pos $source < length $source)
72             {
73 340 50       1095 if ($source =~ m/(\G\s*use\s+Acme::Gosub\b)/gc)
74             {
75 0         0 $text .= q{use Acme::Gosub 'noimport'};
76 0         0 next component;
77             }
78 340         1536 my @pos = Text::Balanced::_match_quotelike(\$source,qr/\s*/,1,0);
79 340 100       13970 if (defined $pos[0])
80             {
81 12         32 my $pre = substr($source,$pos[0],$pos[1]); # matched prefix
82 12         38 $text .= $pre . substr($source,$pos[2],$pos[18]-$pos[2]);
83 12         52 next component;
84             }
85 328 50       2323 if ($source =~ m/\G\s*($pod_or_DATA)/gc) {
86 0         0 next component;
87             }
88 328         1539 @pos = Text::Balanced::_match_variable(\$source,qr/\s*/);
89 328 100       17720 if (defined $pos[0])
90             {
91 37 100       119 $text .= " " if $pos[0] < $pos[2];
92 37         90 $text .= substr($source,$pos[0],$pos[4]-$pos[0]);
93 37         155 next component;
94             }
95              
96 291 100       1553 if ($source =~ m/\G(\n*)(\s*)gosub\b/gc)
    100          
97             {
98 8         41 $text .= "$1$2";
99 8         17 my $arg;
100 8 100       34 if ($source =~ m/\G\s*(\w+)\s*;/gc)
101             {
102 5         15 $arg = $1;
103             }
104             else
105             {
106 3         8 my $pos_source = pos($source);
107             # This is an Evil hack that meant to get Text::Balanced to do
108             # what we want. What happens is that we put an initial ";"
109             # so the end of the statement will be a ";" too.
110 3         19 my $source_for_text_balanced = ";" .
111             substr($source, $pos_source);
112 3         10 pos($source_for_text_balanced) = 0;
113             @pos = Text::Balanced::_match_codeblock(\$source_for_text_balanced,qr/\s*/,qr/;/,qr/;/,qr/[[{(<]/,qr/[]})>]/,undef)
114 3 50       29 or do {
115 0         0 die "Bad gosub statement (problem in the parentheses?) near $Acme::Gosub::file line ", line(substr($source_for_text_balanced,0,pos $source_for_text_balanced),$line), "\n";
116             };
117 3         1590 my $future_pos_source = $pos_source + pos($source_for_text_balanced);
118 3         131 print join(",",@pos), "\n";
119 3         23 $arg = filter_blocks(substr($source_for_text_balanced,1,$pos[4]-$pos[0]),line(substr($source_for_text_balanced,0,1),$line));
120 3         34 print "\$arg = $arg\n";
121 3         15 pos($source) = $future_pos_source;
122             }
123              
124 8         30 my $next_ret_label = "__G_O_S_U_B_RET_LABEL_" .
125             ($next_label_idx++);
126              
127 8         29 $text .= "push \@{\$Acme::Gosub::ret_labels{(caller(0))[3]}}, \"$next_ret_label\";";
128 8         23 $text .= "goto $arg;";
129 8         27 $text .= "$next_ret_label:";
130 8         39 next component;
131             }
132             elsif ($source =~ m/\G(\s*)greturn\s*;/gc)
133             {
134 4         15 $text .= $1;
135 4         31 $text .= "goto (pop(\@{\$Acme::Gosub::ret_labels{(caller(0))[3]}}));";
136 4         18 next component;
137             }
138              
139 279         1140 $source =~ m/\G(\s*(-[sm]\s+|\w+|#.*\n|\W))/gc;
140 279         1283 $text .= $1;
141             }
142 1         31 $text;
143             }
144              
145             1;
146              
147             __END__