File Coverage

blib/lib/Debug/Filter/PrintExpr.pm
Criterion Covered Total %
statement 79 81 97.5
branch 20 22 90.9
condition 6 7 85.7
subroutine 23 23 100.0
pod n/a
total 128 133 96.2


line stmt bran cond sub pod time code
1             package Debug::Filter::PrintExpr;
2              
3 2     2   98699 use strict;
  2         10  
  2         59  
4 2     2   10 use warnings;
  2         4  
  2         46  
5            
6 2     2   40 use 5.010;
  2         6  
7 2     2   1122 use Filter::Simple;
  2         47596  
  2         13  
8 2     2   115 use Scalar::Util qw(isdual blessed);
  2         4  
  2         131  
9 2     2   14 use List::Util 'pairs';
  2         4  
  2         151  
10 2     2   1322 use Data::Dumper;
  2         13553  
  2         134  
11 2     2   14 use B qw(svref_2object SVf_IOK SVp_IOK SVf_NOK SVp_NOK);
  2         385  
  2         1265  
12              
13             our
14             $VERSION = '0.19';
15              
16             # variable is exposed and my be overwritten by caller
17             our $handle = *STDERR;
18              
19             # helper function: tests if given variable has data
20             # in it's "numeric slot"
21             sub _isnumeric {
22 25     25   203 return svref_2object(\$_[0])->FLAGS &
23             (SVf_IOK | SVp_IOK | SVf_NOK | SVp_NOK);
24             }
25              
26             # generate a prefix containing line number or custom label
27             # consume first three args, return number of printed chars
28             # if no expression is present
29             sub _genprefix {
30 29     29   81 my ($label, $line, $expr, $pos) = splice @_, 0, 3;
31 29         65 local ($,, $\);
32 29   66     242 printf $handle "%s%n", $label || "L$line:", $pos;
33 29 100       124 print $handle $expr ? " $expr = " : " ";
34 29 100       161 return $expr ? undef : $pos + 1;
35             }
36              
37             # create representation of single value
38             sub _singlevalue {
39 25     25   55 my ($val, $str, $num) = shift;
40 25         67 my $isdual = isdual($val);
41 25         48 my $isnumeric = _isnumeric($val);
42 25 100       77 $str = "$val" if defined $val;
43 25 100       53 $num = $val + 0 if $isnumeric;
44 25 100       99 if (!defined $val) {
    50          
    50          
    100          
    100          
45 1         5 return 'undef';
46             } elsif (my $class = blessed($val)) {
47 0         0 return "blessed($class)";
48             } elsif (ref($val)) {
49 0         0 return $val;
50             } elsif ($isdual) {
51 3         16 return "dualvar($num, '$str')";
52             } elsif ($isnumeric) {
53 8         38 return $num;
54             } else {
55 13         68 return "'$str'";
56             }
57             }
58              
59             # print out an expression in scalar context
60             sub _valuescalar {
61 21     21   46 local ($,, $\);
62 21         56 print $handle _singlevalue($_[0]);
63             }
64              
65             # print out an expression in list context
66             sub _valuearray {
67 2     2   5 local ($,, $\);
68             print $handle '(', join(', ',
69 2         9 map({_singlevalue($_)} @_)), ");\n";
  2         4  
70             }
71              
72             # print out an expression as key-value pairs
73             sub _valuehash {
74 2     2   5 local ($,, $\);
75             print $handle '(', join(", ",
76             map(
77 2         19 {"'$_->[0]' => " . _singlevalue($_->[1])}
  2         13  
78             pairs(@_))), ");\n";
79             }
80              
81             # process a scalar debug statement
82             sub _print_scalar {
83 23     23   16444 local ($,, $\);
84 23 100       47 unless (&_genprefix) {
85 21         67 _valuescalar($_[0]);
86 21         59 print $handle ';';
87             }
88 23         87 print $handle "\n";
89             }
90              
91             # process a string scalar debug statement
92             sub _print_str {
93 2     2   867 my $val = $_[3];
94 2         7 splice @_, 3, 1, "$val";
95 2         7 goto &_print_scalar;
96             }
97              
98             # process a numeric scalar debug statement
99             sub _print_num {
100 2     2   22 no warnings qw(numeric);
  2         5  
  2         1032  
101 2     2   794 my $val = $_[3];
102 2         7 splice @_, 3, 1, $val + 0;
103 2         8 goto &_print_scalar;
104             }
105              
106             # process an array debug statement
107             sub _print_array {
108 2     2   854 &_genprefix;
109 2         9 goto &_valuearray;
110             }
111              
112             # process a hash debug statement
113             sub _print_hash {
114 2     2   827 &_genprefix;
115 2         7 goto &_valuehash;
116             }
117              
118             # process a reference debug statement
119             sub _print_ref {
120 2     2   3767 my $expr = splice @_, 2, 1, undef;
121 2         5 my $skip = &_genprefix;
122 2         5 local ($,, $\);
123 2         8 print $handle "dump($expr);\n";
124 2         21 print $handle
125             Data::Dumper->new([@_], [map("_[$_]", (0 .. $#_))])
126             ->Pad(' ' x $skip)->Dump;
127             }
128              
129             # type classifications: print function suffix + is scalar
130             my %type_defs = (
131             '$' => ['scalar', 1],
132             '"' => ['str', 1],
133             '#' => ['num', 1],
134             '@' => ['array', 0],
135             '%' => ['hash', 0],
136             '\\' => ['ref', 0],
137             );
138              
139             # process a debug statement, runs in filter context
140             sub _gen_print {
141 29   100 29   265 my ($type, $label, $expr) = map $_ // '', @_;
142 29   100     71 my $val = $_[2] // '()';
143 29         42 my ($ptype, $scalar) = @{$type_defs{$type}};
  29         55  
144 29         57 my $print = __PACKAGE__ . "::_print_$ptype";
145 29 100       240 return qq[{$print("$label", __LINE__, q{$expr}, ] .
146             ($scalar ? qq[scalar($val)] : qq[$val]) .
147             q[)}];
148             }
149              
150             # source code processing happens here
151             FILTER {
152             my ($self, @args) = @_;
153             my $debug;
154             $debug ||= grep /^-debug$/, @args;
155             s/
156             ^\h*+\#
157             (?[%@\$\\#"])
158             \{\h*+
159             (?
160             \h*+
161             (?\V*[^\s])?\h*
162             \}\h*+\r?$
163 2     2   978 / _gen_print($+{type}, $+{label}, $+{expr}) /gmex;
  2         751  
  2         380  
164             print STDERR if $debug;
165             };
166              
167             1;
168              
169             __END__