line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Lexical::Types; |
2
|
|
|
|
|
|
|
|
3
|
15
|
|
|
15
|
|
777182
|
use 5.008_004; |
|
15
|
|
|
|
|
188
|
|
4
|
|
|
|
|
|
|
|
5
|
15
|
|
|
15
|
|
110
|
use strict; |
|
15
|
|
|
|
|
41
|
|
|
15
|
|
|
|
|
457
|
|
6
|
15
|
|
|
15
|
|
98
|
use warnings; |
|
15
|
|
|
|
|
37
|
|
|
15
|
|
|
|
|
1122
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 NAME |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
Lexical::Types - Extend the semantics of typed lexicals. |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 VERSION |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
Version 0.16 |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=cut |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
our $VERSION; |
19
|
|
|
|
|
|
|
BEGIN { |
20
|
15
|
|
|
15
|
|
882
|
$VERSION = '0.16'; |
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 SYNOPSIS |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
{ package Str; } |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
{ |
28
|
|
|
|
|
|
|
package My::Types::Str; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub new { bless { }, shift } |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
use Lexical::Types as => sub { 'My::Types::' . $_[0] => 'new' }; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
my Str $x; # $x is now a My::Types::Str object |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
{ |
38
|
|
|
|
|
|
|
package My::Types::Int; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub TYPEDSCALAR { bless { }, shift } |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
use Lexical::Types; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
use constant Int => 'My::Types::Int'; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
my Int $y; # $y is now a My::Types::Int object |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=head1 DESCRIPTION |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
This pragma allows you to hook the execution of typed lexicals declarations (C) by calling a configurable method in a configurable package at each run. |
52
|
|
|
|
|
|
|
In particular, it can be used to automatically tie or bless typed lexicals whenever they are initialized. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
Remind that for C to be able to parse C, you need : |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=over 4 |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=item * |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
either the C package to be defined ; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=item * |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
or for C to be a constant sub returning a valid defined package. |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=back |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
so make sure you follow one of those two strategies to define your types. |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
This pragma is B implemented with a source filter. |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=cut |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
BEGIN { |
75
|
15
|
|
|
15
|
|
113
|
require XSLoader; |
76
|
15
|
|
|
|
|
13199
|
XSLoader::load(__PACKAGE__, $VERSION); |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head1 METHODS |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=head2 C |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
use Lexical::Types; |
84
|
|
|
|
|
|
|
use Lexical::Types as => $prefix; |
85
|
|
|
|
|
|
|
use Lexical::Types as => sub { ... }; # = $mangler |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Magically called when C |
88
|
|
|
|
|
|
|
All the occurences of C in the current lexical scope will be changed to call at each run a given method in a given package. |
89
|
|
|
|
|
|
|
The method and package are determined by the parameter C<'as'> : |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=over 4 |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=item * |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
If it's left unspecified, the C method in the C package will be called. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
use Lexical::Types; |
98
|
|
|
|
|
|
|
my Str $x; # calls Str->TYPEDSCALAR |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=item * |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
If a plain scalar C<$prefix> is passed as the value, the C method in the C<${prefix}::Str> package will be used. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
use Lexical::Types as => 'My::'; # or "as => 'My'" |
105
|
|
|
|
|
|
|
my Str $x; # calls My::Str->TYPEDSCALAR |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=item * |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
If the value given is a code reference C<$mangler>, it will be called at compile-time with arguments C<'Str'> and C<'TYPEDSCALAR'> and is expected to return : |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=over 4 |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=item * |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
either an empty list, in which case the current typed lexical definition will be skipped (thus it won't be altered to trigger a run-time hook) ; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
use Lexical::Types as => sub { |
118
|
|
|
|
|
|
|
return $_[0] =~ /Str/ ? @_ : () |
119
|
|
|
|
|
|
|
}; |
120
|
|
|
|
|
|
|
my Str $y; # calls Str->TYPEDSCALAR |
121
|
|
|
|
|
|
|
my Int $x; # nothing special |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=item * |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
or the desired package and method name, in that order (if any of those is C, the default value will be used instead). |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
use Lexical::Types as => sub { 'My', 'new_' . lc($_[0]) }; |
128
|
|
|
|
|
|
|
my Str $x; # the coderef indicates to call My->new_str |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=back |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
Note that if the type is a constant, C<$_[0]> will be set to the I of constant and not to its name. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
use Lexical::Types as => sub { $_[0] => 'new' }; |
135
|
|
|
|
|
|
|
use constant Str => 'MyStr'; |
136
|
|
|
|
|
|
|
my Str $x; # calls MyStr->new |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
This means in particular that you can't both use constant types and redirect several types to different methods of the same package, because then you can't distinguish between the original types with C<$_[0]>. |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=back |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=cut |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub import { |
145
|
1040
|
|
|
1040
|
|
789426
|
shift; |
146
|
1040
|
|
|
|
|
2742
|
my %args = @_; |
147
|
|
|
|
|
|
|
|
148
|
1040
|
|
|
|
|
1707
|
my $hint; |
149
|
|
|
|
|
|
|
|
150
|
1040
|
|
|
|
|
2122
|
my $as = delete $args{'as'}; |
151
|
1040
|
100
|
|
|
|
2525
|
if ($as) { |
152
|
23
|
|
|
|
|
68
|
my $r = ref $as; |
153
|
23
|
100
|
|
|
|
85
|
if ($r eq 'CODE') { |
|
|
100
|
|
|
|
|
|
154
|
17
|
|
|
|
|
71
|
$hint = _tag($as); |
155
|
|
|
|
|
|
|
} elsif (!$r) { |
156
|
5
|
100
|
|
|
|
32
|
$as .= '::' if $as !~ /::$/; |
157
|
5
|
|
|
8
|
|
32
|
$hint = _tag(sub { $as . $_[0] }); |
|
8
|
|
|
|
|
4880
|
|
158
|
|
|
|
|
|
|
} else { |
159
|
1
|
|
|
|
|
12
|
require Carp; |
160
|
1
|
|
|
|
|
243
|
Carp::croak("Invalid $r reference for 'as'"); |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
} else { |
163
|
1017
|
|
|
1071
|
|
6143
|
$hint = _tag(sub { @_ }); |
|
1071
|
|
|
|
|
74862
|
|
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
1039
|
|
|
|
|
3364
|
$^H |= 0x020000; |
167
|
1039
|
|
|
|
|
5056
|
$^H{+(__PACKAGE__)} = $hint; |
168
|
|
|
|
|
|
|
|
169
|
1039
|
|
|
|
|
12951
|
return; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head2 C |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
no Lexical::Types; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
Magically called when C is encountered. |
177
|
|
|
|
|
|
|
Turns the pragma off. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=cut |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub unimport { |
182
|
2
|
|
|
2
|
|
78
|
$^H |= 0x020000; |
183
|
2
|
|
|
|
|
7
|
$^H{+(__PACKAGE__)} = undef; |
184
|
|
|
|
|
|
|
|
185
|
2
|
|
|
|
|
101
|
return; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=head1 RUN-TIME INITIALIZER METHOD |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
The initializer method receives an alias to the pad slot of the initialized lexical in C<$_[1]> and the original type name in C<$_[2]>. |
191
|
|
|
|
|
|
|
You can either edit C<$_[1]> in place, in which case you should return an empty list, or return a new scalar that will be copied into the pad slot. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
use Lexical::Types as => 'My'; |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
my Str $x; |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
... |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub My::Str::TYPEDSCALAR { |
200
|
|
|
|
|
|
|
# $_[1] is an alias to $x, and $_[2] is 'Str' |
201
|
|
|
|
|
|
|
... |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=head1 INTEGRATION |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
You can integrate L in your module so that using it will provide types to your users without asking them to load either L or the type classes manually. |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
package MyTypes; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
BEGIN { require Lexical::Types; } |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub import { |
213
|
|
|
|
|
|
|
eval 'package Str; package Int'; # The types you want to support |
214
|
|
|
|
|
|
|
Lexical::Types->import( |
215
|
|
|
|
|
|
|
as => sub { __PACKAGE__, 'new_' . lc($_[0]) } |
216
|
|
|
|
|
|
|
); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub unimport { |
220
|
|
|
|
|
|
|
Lexical::Types->unimport; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub new_str { ... } |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub new_int { ... } |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
If you prefer to use constants rather than creating empty packages, you can replace the previous example with something like this : |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
package MyTypes; |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
BEGIN { require Lexical::Types; } |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub import { |
234
|
|
|
|
|
|
|
my $pkg = caller; |
235
|
|
|
|
|
|
|
for (qw) { |
236
|
|
|
|
|
|
|
my $type = __PACKAGE__ . '::' . $_; |
237
|
|
|
|
|
|
|
no strict 'refs'; |
238
|
|
|
|
|
|
|
no warnings 'redefine'; |
239
|
|
|
|
|
|
|
*{$pkg.'::'.$_} = eval "sub () { '$type' }"; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
Lexical::Types->import( |
242
|
|
|
|
|
|
|
as => sub { $_[0] => 'new' } |
243
|
|
|
|
|
|
|
); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub unimport { |
247
|
|
|
|
|
|
|
Lexical::Types->unimport; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
package MyTypes::Str; |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub new { ... } |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
package MyTypes::Int; |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub new { ... } |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head1 CONSTANTS |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=head2 C |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
True iff the module could have been built with thread-safety features enabled. |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=head2 C |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
True iff this module could have been built with fork-safety features enabled. |
267
|
|
|
|
|
|
|
This will always be true except on Windows where it's false for perl 5.10.0 and below . |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=head1 CAVEATS |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Using this pragma will cause a slight global slowdown of any subsequent compilation phase that happens anywere in your code - even outside of the scope of use of C |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
The restrictions on the type (being either a defined package name or a constant) apply even if you use the C<'as'> option to redirect to another package, and are unlikely to find a workaround as this happens deep inside the lexer - far from the reach of an extension. |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
Only one mangler or prefix can be in use at the same time in a given scope. |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
Typed lexicals declarations that appear in code C'd during the global destruction phase of a spawned thread or pseudo-fork (the processes used internally for the C emulation on Windows) are ignored. |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
The implementation was tweaked to work around several limitations of vanilla C pragmas : it's thread safe, and doesn't suffer from a C bug that causes all pragmas to propagate into Cd scopes. |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
With 5.8 perls, the pragma does not propagate into C. |
282
|
|
|
|
|
|
|
This is due to a shortcoming in the way perl handles the hints hash, which is addressed in perl 5.10. |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=head1 DEPENDENCIES |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
L 5.8.4. |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
A C compiler. |
289
|
|
|
|
|
|
|
This module may happen to build with a C++ compiler as well, but don't rely on it, as no guarantee is made in this regard. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
L (standard since perl 5.6.0). |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=head1 SEE ALSO |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
L. |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
L. |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=head1 AUTHOR |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
Vincent Pit, C<< >>, L. |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
You can contact me by mail or on C (vincent). |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=head1 BUGS |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through the web interface at L. |
308
|
|
|
|
|
|
|
I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=head1 SUPPORT |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
perldoc Lexical::Types |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Inspired by Ricardo Signes. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
Thanks Florian Ragwitz for suggesting the use of constants for types. |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
Copyright 2009,2010,2011,2012,2013,2014,2015,2017 Vincent Pit, all rights reserved. |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=cut |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
1; # End of Lexical::Types |