line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Whatever;
|
2
|
2
|
|
|
2
|
|
51651
|
use warnings;
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
62
|
|
3
|
2
|
|
|
2
|
|
9
|
use strict;
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
55
|
|
4
|
2
|
|
|
2
|
|
9
|
use Carp ();
|
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
1140
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
sub star (&) {
|
7
|
|
|
|
|
|
|
my $code = shift;
|
8
|
|
|
|
|
|
|
bless sub :lvalue {
|
9
|
|
|
|
|
|
|
goto &$code if @_ < 2;
|
10
|
|
|
|
|
|
|
my $star = $code;
|
11
|
|
|
|
|
|
|
{$star = $star->(shift);
|
12
|
|
|
|
|
|
|
@_ and ref $star eq 'Whatever' ? redo
|
13
|
|
|
|
|
|
|
: Carp::croak 'too many arguments for Whatever'}
|
14
|
|
|
|
|
|
|
$star
|
15
|
|
|
|
|
|
|
}
|
16
|
|
|
|
|
|
|
}
|
17
|
8
|
|
|
|
|
69
|
use overload fallback => 1,
|
18
|
|
|
|
|
|
|
(# infix
|
19
|
|
|
|
|
|
|
map {
|
20
|
6
|
50
|
|
|
|
347
|
my $code = /atan2/ ? sub {atan2 $_[0], $_[1]}
|
21
|
58
|
100
|
|
|
|
3254
|
: eval "sub {\$_[0] $_ \$_[1]}" or die $@;
|
|
|
50
|
|
|
|
|
|
22
|
|
|
|
|
|
|
$_ => sub {
|
23
|
688
|
|
|
688
|
|
9493
|
my ($self, $flip) = @_[0, 2];
|
24
|
688
|
|
|
|
|
758
|
my $arg2 = \$_[1];
|
25
|
|
|
|
|
|
|
star {
|
26
|
1061
|
100
|
|
1061
|
|
2569
|
$code->($flip ? ($$arg2, &$self)
|
27
|
|
|
|
|
|
|
: (&$self, $$arg2))
|
28
|
|
|
|
|
|
|
}
|
29
|
688
|
|
|
|
|
2211
|
}
|
30
|
58
|
|
|
|
|
261
|
} qw (+ - * / % ** << >> x . & | ^ < <= > >= == != lt le gt
|
31
|
|
|
|
|
|
|
ge eq ne <=> cmp atan2), $^V >= 5.010 ? '~~' : ()
|
32
|
|
|
|
|
|
|
),
|
33
|
|
|
|
|
|
|
(# prefix
|
34
|
|
|
|
|
|
|
map {
|
35
|
12
|
50
|
|
|
|
653
|
my $code = eval "sub {$_ \$_[0]}" or die $@;
|
36
|
|
|
|
|
|
|
($_ eq '-' ? 'neg' : $_) => sub {
|
37
|
2
|
|
|
2
|
|
5
|
my $self = $_[0];
|
38
|
12
|
|
|
12
|
|
21
|
star {$code->(&$self)}
|
39
|
2
|
|
|
|
|
9
|
}
|
40
|
6
|
100
|
|
|
|
37
|
} qw (- ! ~)
|
41
|
|
|
|
|
|
|
),
|
42
|
|
|
|
|
|
|
(# functions
|
43
|
|
|
|
|
|
|
map {
|
44
|
36
|
|
|
36
|
|
130
|
my $code = eval "sub {$_(\$_[0])}" or die $@;
|
45
|
|
|
|
|
|
|
$_ => sub {
|
46
|
1
|
|
|
1
|
|
7754
|
my $self = $_[0];
|
47
|
1
|
|
|
1
|
|
5
|
star {$code->(&$self)}
|
48
|
1
|
|
|
|
|
21
|
}
|
49
|
12
|
|
|
|
|
77
|
} qw (cos sin exp abs log sqrt)
|
50
|
|
|
|
|
|
|
),
|
51
|
36
|
|
|
|
|
146
|
'@{}' => sub {tie my @ret => 'Whatever::ARRAY', shift; \@ret},
|
52
|
2
|
50
|
|
2
|
|
1650
|
'%{}' => sub {tie my %ret => 'Whatever::HASH', shift; \%ret};
|
|
2
|
|
|
26
|
|
943
|
|
|
2
|
|
|
|
|
59
|
|
|
26
|
|
|
|
|
90
|
|
|
26
|
|
|
|
|
116
|
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
{
|
55
|
|
|
|
|
|
|
my $star = star sub :lvalue {@_ ? $_[0] : $_};
|
56
|
|
|
|
|
|
|
my $arg = star sub :lvalue {$_[0]};
|
57
|
|
|
|
|
|
|
my $it = star sub :lvalue {$_};
|
58
|
90
|
|
|
90
|
|
48170
|
** = sub :lvalue {my $x = $star};
|
59
|
0
|
|
|
0
|
|
0
|
*@ = sub {$arg};
|
60
|
7
|
|
|
7
|
|
1481
|
*_ = sub {$it};
|
61
|
|
|
|
|
|
|
** = \$star;
|
62
|
|
|
|
|
|
|
}
|
63
|
|
|
|
|
|
|
eval {Internals::SvREADONLY($*, 1)}
|
64
|
|
|
|
|
|
|
or warn 'Whatever could not set $* readonly: '.$@;
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
my $av_push = eval {
|
67
|
|
|
|
|
|
|
require Array::RefElem;
|
68
|
|
|
|
|
|
|
\&Array::RefElem::av_push
|
69
|
|
|
|
|
|
|
};
|
70
|
|
|
|
|
|
|
sub AUTOLOAD {
|
71
|
17
|
|
|
17
|
|
70
|
my $self = shift;
|
72
|
17
|
|
|
|
|
21
|
my $args = \@_;
|
73
|
17
|
|
|
|
|
29
|
my $method = substr our $AUTOLOAD, 2 + length __PACKAGE__;
|
74
|
|
|
|
|
|
|
star {
|
75
|
28
|
50
|
|
28
|
|
45
|
if ($av_push) {
|
76
|
|
|
|
|
|
|
$av_push->(\@_, $_)
|
77
|
0
|
|
|
|
|
0
|
for scalar &$self, @$args, @_ = ();
|
78
|
|
|
|
|
|
|
} else {
|
79
|
28
|
|
|
|
|
41
|
@_ = (scalar &$self, @$args)
|
80
|
|
|
|
|
|
|
}
|
81
|
28
|
|
|
|
|
76
|
goto &{$_[0]->can($method)}
|
|
28
|
|
|
|
|
92
|
|
82
|
|
|
|
|
|
|
}
|
83
|
17
|
|
|
0
|
|
65
|
} sub DESTROY {}
|
|
0
|
|
|
|
|
0
|
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
{package
|
86
|
|
|
|
|
|
|
Whatever::ARRAY;
|
87
|
36
|
|
|
36
|
|
82
|
sub TIEARRAY {bless \\pop}
|
88
|
|
|
|
|
|
|
sub FETCH {
|
89
|
37
|
|
|
37
|
|
119
|
my ($self, $key) = @_;
|
90
|
|
|
|
|
|
|
Whatever::star sub :lvalue {
|
91
|
38
|
|
100
|
38
|
|
78
|
(&$$$self ||= [])->[$key - ($key > 2**30 and 2**31-1)]
|
|
|
|
100
|
|
|
|
|
92
|
|
|
|
|
|
|
}
|
93
|
37
|
|
|
|
|
147
|
}
|
94
|
3
|
|
|
3
|
|
10
|
sub FETCHSIZE {2**31-1}
|
95
|
1
|
|
|
1
|
|
169
|
sub AUTOLOAD {Carp::croak our $AUTOLOAD . " unsupported"}
|
96
|
0
|
|
|
0
|
|
0
|
sub DESTROY {}
|
97
|
|
|
|
|
|
|
}
|
98
|
|
|
|
|
|
|
{package
|
99
|
|
|
|
|
|
|
Whatever::HASH;
|
100
|
26
|
|
|
26
|
|
62
|
sub TIEHASH {bless \\pop}
|
101
|
|
|
|
|
|
|
sub FETCH {
|
102
|
25
|
|
|
25
|
|
40
|
my ($self, $key) = @_;
|
103
|
30
|
|
100
|
30
|
|
65
|
Whatever::star sub :lvalue {(&$$$self ||= {})->{$key}}
|
104
|
25
|
|
|
|
|
85
|
}
|
105
|
1
|
|
|
1
|
|
103
|
sub AUTOLOAD {Carp::croak our $AUTOLOAD . " unsupported"}
|
106
|
0
|
|
|
0
|
|
|
sub DESTROY {}
|
107
|
|
|
|
|
|
|
}
|
108
|
|
|
|
|
|
|
delete $Whatever::{star};
|
109
|
|
|
|
|
|
|
our $VERSION = '0.23';
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=head1 NAME
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
Whatever - a perl6ish whatever-star for perl5
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=head1 VERSION
|
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
Version 0.23
|
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
this module provides a whatever-star C< * > term for perl 5. since this
|
122
|
|
|
|
|
|
|
module is B a source filter, the name C< &* > or C< $* > is as close as
|
123
|
|
|
|
|
|
|
it's going to get.
|
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
use Whatever;
|
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
my $greet = 'hello, ' . &* . '!';
|
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
say $greet->('world'); # prints 'hello, world!'
|
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
what was:
|
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
my $result = $someobj->map(sub{$_ * 2});
|
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
can now be:
|
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
my $result = $someobj->map(&* * 2);
|
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=head1 EXPORT
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
&* the whatever-star
|
142
|
|
|
|
|
|
|
$* the whatever-star ($* is deprecated in 5.10+, so I'm taking it)
|
143
|
|
|
|
|
|
|
&@ the gets-val-from-@_-star
|
144
|
|
|
|
|
|
|
&_ the gets-val-from-$_-star
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
like all punctuation variables, the whatever terms are global across all
|
147
|
|
|
|
|
|
|
packages after this module is loaded.
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=head1 SUBROUTINES
|
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
the C< &* > and C< $* > stars are the most generic terms, which return their
|
152
|
|
|
|
|
|
|
expression as a coderef that will take its argument from C< $_[0] > if it is
|
153
|
|
|
|
|
|
|
available, or C< $_ > otherwise. this allows the terms to dwim in most contexts.
|
154
|
|
|
|
|
|
|
think of the whatever star as C< sub {@_ ? $_[0] : $_} >
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
the C< &@ > term always uses C< $_[0]>, while the C< &_ > always uses C< $_ >
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
beyond where they get their eventual argument from, all of the whatever terms
|
159
|
|
|
|
|
|
|
behave the same way. each is a I overloaded object that will bind to
|
160
|
|
|
|
|
|
|
the operators and variables that it interacts with. at all times the whatever
|
161
|
|
|
|
|
|
|
star is a coderef that will perform the actions it has accumulated when passed
|
162
|
|
|
|
|
|
|
a value to act on.
|
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
a few more examples are probably in order:
|
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=over 4
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=item hello world
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
my $greet = "hello, $*!"; # the $* term interpolates in strings
|
171
|
|
|
|
|
|
|
say $greet->('world'); # prints 'hello, world!'
|
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
say "hello, $*!"->('world');
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=item simple operations
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
my $inc = $* + 1;
|
178
|
|
|
|
|
|
|
say $inc->(5); # prints 6
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
my $inc_x2 = $inc * 2; # whatever code continues to capture operations
|
181
|
|
|
|
|
|
|
say $inc_x2->(5); # prints 12
|
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
my $inc_inc = $inc->($inc); # and is fine with recursion
|
184
|
|
|
|
|
|
|
say $inc_inc->(5); # prints 7
|
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
my $repeat = &* x &*;
|
187
|
|
|
|
|
|
|
my $line = $repeat->('-');
|
188
|
|
|
|
|
|
|
my $hr = $line . "\n";
|
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
print $hr->(80); # prints ('-' x 80)."\n"
|
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=item with object oriented code
|
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
assuming this simple C< Array > implementation:
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
{package Array;
|
197
|
|
|
|
|
|
|
sub new {shift; bless [@_]}
|
198
|
|
|
|
|
|
|
sub map {new Array map $_[1]() => @{$_[0]}}
|
199
|
|
|
|
|
|
|
sub grep {new Array grep $_[1]() => @{$_[0]}}
|
200
|
|
|
|
|
|
|
sub str {join ' ' => @{$_[0]}}
|
201
|
|
|
|
|
|
|
}
|
202
|
|
|
|
|
|
|
my $array = new Array 1 .. 10;
|
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
say $array->map(&_ * 2)->str; # '2 4 6 8 10 12 14 16 18 20'
|
205
|
|
|
|
|
|
|
say $array->map(&_ * 2)->map(&_ + 1)->str; # '3 5 7 9 11 13 15 17 19 21'
|
206
|
|
|
|
|
|
|
say $array->map(&_ * 2 + 1)->str; # '3 5 7 9 11 13 15 17 19 21'
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=item method calls
|
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
my $str = &*->str;
|
211
|
|
|
|
|
|
|
say $str->($array); # prints '1 2 3 4 5 6 7 8 9 10'
|
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
my $multi_call = &*->map(&_ * 2 + 1)->grep(&_ % 5)->str;
|
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
say $multi_call->($array); # prints '3 7 9 11 13 17 19 21'
|
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
$some_obj->map(&*->some_method(...));
|
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
arguments of method calls are copied by alias if L is installed.
|
220
|
|
|
|
|
|
|
this provides closure like behavior. otherwise, the values are fixed to
|
221
|
|
|
|
|
|
|
whatever they were at the time of declaration.
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=item multiple whatever stars
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
when working with subs created by combining multiple stars, you can bind
|
226
|
|
|
|
|
|
|
multiple values at once by passing multiple arguments.
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
my $join3 = &* . &* . &*;
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
say $join3->(1)(2)(3); # prints '123'
|
231
|
|
|
|
|
|
|
say $join3->(1 .. 3); # prints '123'
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
my $indent = $join3->(' ', ' ');
|
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
say $indent->('xyz'); # prints ' xyz'
|
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=item arrays and hashes
|
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
you can dereference a whatever star as an array or hash (of course the star
|
240
|
|
|
|
|
|
|
expects to be passed a suitable reference):
|
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
my $first = &*->[0];
|
243
|
|
|
|
|
|
|
my $bob = &*->{bob};
|
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
say $first->([3 .. 5]); # prints '3'
|
246
|
|
|
|
|
|
|
say $bob->({bob => 5}); # prints '5'
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
the subroutine returned by the star is a valid lvalue (can be assigned to).
|
249
|
|
|
|
|
|
|
multi-level calls and calls that would normally autovivify behave as expected.
|
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
&*->[0][0]{x}(my $array) = 4;
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
say $$array[0][0]{x}; # prints '4'
|
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=item variables
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
the stars lazily bind to variables, which allows the variable to get its value
|
258
|
|
|
|
|
|
|
after the star is defined, and to change its value between calls. this is
|
259
|
|
|
|
|
|
|
analogous to an anonymous sub closing over a variable
|
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
my $future;
|
262
|
|
|
|
|
|
|
my $delorean = $future . (' ' . $* . '!');
|
263
|
|
|
|
|
|
|
# works like: sub {$future . (' ' . $_[0] . '!')};
|
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
$future = 1.21;
|
266
|
|
|
|
|
|
|
say $delorean->('gigawatts'); # prints "1.21 gigawatts!"
|
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
$future = &*;
|
269
|
|
|
|
|
|
|
say $delorean->('folks')->("that's all"); # prints "that's all folks!"
|
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=back
|
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=head1 AUTHOR
|
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
Eric Strom, C<< >>
|
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head1 BUGS
|
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
this module is new, there are probably some.
|
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
please report any bugs or feature requests to C,
|
282
|
|
|
|
|
|
|
or through the web interface at
|
283
|
|
|
|
|
|
|
L. I will be
|
284
|
|
|
|
|
|
|
notified, and then you'll automatically be notified of progress on your bug as
|
285
|
|
|
|
|
|
|
I make changes.
|
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS
|
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
those behind the perl6 whatever-star
|
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT
|
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
copyright 2010 Eric Strom.
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
this program is free software; you can redistribute it and/or modify it
|
296
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published
|
297
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License.
|
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
see http://dev.perl.org/licenses/ for more information.
|
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=cut
|
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
__PACKAGE__ if 'first require';
|