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.9';
3 2     2   112830 use strict;
  2         23  
  2         51  
4 2     2   8 use warnings;
  2         4  
  2         49  
5 2     2   8 use Carp qw/ croak /;
  2         3  
  2         76  
6              
7             # LOAD FILTERING MODULE...
8 2     2   900 use Filter::Util::Call;
  2         1520  
  2         113  
9              
10             # CATCH ATTEMPTS TO CALL case OUTSIDE THE SCOPE OF ANY switch
11              
12             my $next_label_idx = 0;
13 2     2   11 use vars qw(%ret_labels);
  2         3  
  2         477  
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   26 $fallthrough = grep /\bfallthrough\b/, @_;
23 2         7 $offset = (caller)[2]+1;
24 2 50 33     24 filter_add({}) unless @_>1 && $_[1] eq 'noimport';
25 2         51 my $pkg = caller;
26 2         20 1;
27             }
28              
29             sub unimport
30             {
31 0     0   0 filter_del()
32             }
33              
34             sub filter
35             {
36 4     4 1 780 my($self) = @_ ;
37 4         14 local $Acme::Gosub::file = (caller)[1];
38              
39 4         9 my $status = 1;
40 4         93 $status = filter_read(1_000_000);
41 4 50       17 return $status if $status<0;
42 4         20 $_ = filter_blocks($_,$offset);
43 4 100       22 $_ = "# line $offset\n" . $_ if $offset; undef $offset;
  4         49  
44 4         3150 return $status;
45             }
46              
47 2     2   1098 use Text::Balanced ':ALL';
  2         31200  
  2         1837  
48              
49             sub line
50             {
51 3     3 1 10 my ($pretext,$offset) = @_;
52 3   50     16 ($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 19 my ($source, $line) = @_;
68 7 100       47 return $source unless $source =~ /gosub|greturn/;
69 1         4 pos $source = 0;
70 1         2 my $text = "";
71 1         3 component: while (pos $source < length $source)
72             {
73 340 50       587 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         826 my @pos = Text::Balanced::_match_quotelike(\$source,qr/\s*/,1,0);
79 340 100       7396 if (defined $pos[0])
80             {
81 12         16 my $pre = substr($source,$pos[0],$pos[1]); # matched prefix
82 12         19 $text .= $pre . substr($source,$pos[2],$pos[18]-$pos[2]);
83 12         27 next component;
84             }
85 328 50       1180 if ($source =~ m/\G\s*($pod_or_DATA)/gc) {
86 0         0 next component;
87             }
88 328         802 @pos = Text::Balanced::_match_variable(\$source,qr/\s*/);
89 328 100       9640 if (defined $pos[0])
90             {
91 37 100       68 $text .= " " if $pos[0] < $pos[2];
92 37         57 $text .= substr($source,$pos[0],$pos[4]-$pos[0]);
93 37         79 next component;
94             }
95              
96 291 100       857 if ($source =~ m/\G(\n*)(\s*)gosub\b/gc)
    100          
97             {
98 8         19 $text .= "$1$2";
99 8         9 my $arg;
100 8 100       22 if ($source =~ m/\G\s*(\w+)\s*;/gc)
101             {
102 5         8 $arg = $1;
103             }
104             else
105             {
106 3         3 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         12 my $source_for_text_balanced = ";" .
111             substr($source, $pos_source);
112 3         5 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       16 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         880 my $future_pos_source = $pos_source + pos($source_for_text_balanced);
118 3         113 print join(",",@pos), "\n";
119 3         17 $arg = filter_blocks(substr($source_for_text_balanced,1,$pos[4]-$pos[0]),line(substr($source_for_text_balanced,0,1),$line));
120 3         23 print "\$arg = $arg\n";
121 3         12 pos($source) = $future_pos_source;
122             }
123              
124 8         17 my $next_ret_label = "__G_O_S_U_B_RET_LABEL_" .
125             ($next_label_idx++);
126              
127 8         14 $text .= "push \@{\$Acme::Gosub::ret_labels{(caller(0))[3]}}, \"$next_ret_label\";";
128 8         13 $text .= "goto $arg;";
129 8         12 $text .= "$next_ret_label:";
130 8         23 next component;
131             }
132             elsif ($source =~ m/\G(\s*)greturn\s*;/gc)
133             {
134 4         6 $text .= $1;
135 4         18 $text .= "goto (pop(\@{\$Acme::Gosub::ret_labels{(caller(0))[3]}}));";
136 4         9 next component;
137             }
138              
139 279         598 $source =~ m/\G(\s*(-[sm]\s+|\w+|#.*\n|\W))/gc;
140 279         749 $text .= $1;
141             }
142 1         43 $text;
143             }
144              
145             1;
146              
147             __END__