File Coverage

blib/lib/Want.pm
Criterion Covered Total %
statement 74 78 94.8
branch 67 74 90.5
condition 22 30 73.3
subroutine 12 12 100.0
pod 5 8 62.5
total 180 202 89.1


line stmt bran cond sub pod time code
1             package Want;
2              
3             require 5.006;
4 7     7   4482 use Carp 'croak';
  7         8  
  7         375  
5 7     7   23 use strict;
  7         7  
  7         110  
6 7     7   20 use warnings;
  7         9  
  7         6630  
7              
8             require Exporter;
9             require DynaLoader;
10              
11             our @ISA = qw(Exporter DynaLoader);
12              
13             our @EXPORT = qw(want rreturn lnoreturn);
14             our @EXPORT_OK = qw(howmany wantref);
15             our $VERSION = '0.29';
16              
17             bootstrap Want $VERSION;
18              
19             my %reftype = (
20             ARRAY => 1,
21             HASH => 1,
22             CODE => 1,
23             GLOB => 1,
24             OBJECT => 1,
25             );
26              
27             sub _wantone {
28 154     154   148 my ($uplevel, $arg) = @_;
29            
30 154         158 my $wantref = wantref($uplevel + 1);
31 154 100 66     721 if ($arg =~ /^\d+$/) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
32 17         44 my $want_count = want_count($uplevel);
33 17   100     71 return ($want_count == -1 || $want_count >= $arg);
34             }
35             elsif (lc($arg) eq 'infinity') {
36 6         27 return (want_count($uplevel) == -1);
37             }
38             elsif ($arg eq 'REF') {
39 2         6 return $wantref;
40             }
41             elsif ($reftype{$arg}) {
42 26         67 return ($wantref eq $arg);
43             }
44             elsif ($arg eq 'REFSCALAR') {
45 3         9 return ($wantref eq 'SCALAR');
46             }
47             elsif ($arg eq 'LVALUE') {
48 15         52 return want_lvalue($uplevel);
49             }
50             elsif ($arg eq 'RVALUE') {
51 7         39 return !want_lvalue($uplevel);
52             }
53             elsif ($arg eq 'VOID') {
54 4         19 return !defined(wantarray_up($uplevel));
55             }
56             elsif ($arg eq 'SCALAR') {
57 11         26 my $gimme = wantarray_up($uplevel);
58 11   66     52 return (defined($gimme) && 0 == $gimme);
59             }
60             elsif ($arg eq 'BOOL' || $arg eq 'BOOLEAN') {
61 47         51 return want_boolean(bump_level($uplevel));
62             }
63             elsif ($arg eq 'LIST') {
64 11         38 return wantarray_up($uplevel);
65             }
66             elsif ($arg eq 'COUNT') {
67 0         0 croak("want: COUNT must be the *only* parameter");
68             }
69             elsif ($arg eq 'ASSIGN') {
70 5         8 return !!wantassign($uplevel + 1);
71             }
72             else {
73 0         0 croak ("want: Unrecognised specifier $arg");
74             }
75             }
76              
77             sub want {
78 164 100 100 164 1 4917 if (@_ == 1 && $_[0] eq 'ASSIGN') {
79 12         12 @_ = (1);
80 12         20 goto &wantassign;
81             }
82 152         191 want_uplevel(1, @_);
83             }
84              
85             # Simulate the propagation of context through a return value.
86             sub bump_level {
87 247     247 0 167 my ($level) = @_;
88 247         158 for(;;) {
89 247         756 my ($p, $r) = parent_op_name($level+1);
90 247 50 66     659 if ($p eq "return"
      33        
91             or $p eq "(none)" && $r =~ /^leavesub(lv)?$/)
92             {
93 0         0 ++$level
94             }
95             else {
96 247         449 return $level
97             }
98             }
99             }
100              
101             sub want_uplevel {
102 152     152 0 178 my ($level, @args) = @_;
103              
104             # Deal with special cases (for RFC21-consistency):
105 152 100       211 if (1 == @args) {
106 132         153 @_ = (1 + $level);
107 132 100       202 goto &wantref if $args[0] eq 'REF';
108 127 100       160 goto &howmany if $args[0] eq 'COUNT';
109 112 50       146 goto &wantassign if $args[0] eq 'ASSIGN';
110             }
111              
112 132         290 for my $arg (map split, @args) {
113 154 100       244 if ($arg =~ /^!(.*)/) {
114 28 100       40 return 0 unless !_wantone(2 + $level, $1);
115             }
116             else {
117 126 100       145 return 0 unless _wantone(2 + $level, $arg);
118             }
119             }
120            
121 74         137 return 1;
122             }
123              
124             sub howmany () {
125 18     18 1 41 my $level = bump_level(@_, 1);
126 18         35 my $count = want_count($level);
127 18 100       32 return ($count < 0 ? undef : $count);
128             }
129              
130             sub wantref {
131 170     170 1 1156 my $level = bump_level(@_, 1);
132 170         367 my $n = parent_op_name($level);
133 170 100 100     846 if ($n eq 'rv2av') {
    100 66        
    100          
    100          
    100          
    100          
    100          
134 16         18 return "ARRAY";
135             }
136             elsif ($n eq 'rv2hv') {
137 18         16 return "HASH";
138             }
139             elsif ($n eq 'rv2cv' || $n eq 'entersub') {
140 9         20 return "CODE";
141             }
142             elsif ($n eq 'rv2gv' || $n eq 'gelem') {
143 2         3 return "GLOB";
144             }
145             elsif ($n eq 'rv2sv') {
146 1         2 return "SCALAR";
147             }
148             elsif ($n eq 'method_call') {
149 2         7 return 'OBJECT';
150             }
151             elsif ($n eq 'multideref') {
152 5         14 return first_multideref_type($level);
153             }
154             else {
155 117         123 return "";
156             }
157             }
158              
159             sub wantassign {
160 17     17 0 17 my $uplevel = shift();
161 17 100       38 return unless want_lvalue($uplevel);
162 12         10 my $r = want_assign(bump_level($uplevel));
163 12 100       14 if (want('BOOL')) {
164 8   66     30 return (defined($r) && 0 != $r);
165             }
166             else {
167 4 50       7 return $r ? (want('SCALAR') ? $r->[$#$r] : @$r) : ();
    50          
168             }
169             }
170              
171             sub double_return :lvalue;
172              
173             sub rreturn (@) {
174 4 100   4 1 433 if (want_lvalue(1)) {
175 1         237 croak "Can't rreturn in lvalue context";
176             }
177              
178             # Extra scope needed to work with perl-5.19.7 or greater.
179             # Prevents the return being optimised out, which is needed
180             # since it's actually going to be used a stack level above
181             # this sub.
182             {
183 3         3 return double_return(@_);
  3         12  
184             }
185             }
186              
187             sub lnoreturn () : lvalue {
188 5 100 66 5 1 204 if (!want_lvalue(1) || !want_assign(1)) {
189 1         124 croak "Can't lnoreturn except in ASSIGN context";
190             }
191              
192             # Extra scope needed to work with perl-5.19.7 or greater.
193             # Prevents the return being optimised out, which is needed
194             # since it's actually going to be used a stack level above
195             # this sub.
196             #
197             # But in older versions of perl, adding the extra scope
198             # causes the error:
199             # Can't modify loop exit in lvalue subroutine return
200             # so we have to check the version.
201 4 50       8 if ($] >= 5.019) {
202 4         11 return double_return(disarm_temp(my $undef));
203             }
204 0           return double_return(disarm_temp(my $undef));
205             }
206              
207             # Some naughty people were relying on these internal methods.
208             *_wantref = \&wantref;
209             *_wantassign = \&wantassign;
210              
211             1;
212              
213             __END__