OpenCores
URL https://opencores.org/ocsvn/an-fpga-implementation-of-low-latency-noc-based-mpsoc/an-fpga-implementation-of-low-latency-noc-based-mpsoc/trunk

Subversion Repositories an-fpga-implementation-of-low-latency-noc-based-mpsoc

[/] [an-fpga-implementation-of-low-latency-noc-based-mpsoc/] [trunk/] [mpsoc/] [Integration_test/] [synthetic_sim/] [perl_lib/] [Exporter/] [Tiny.pm] - Blame information for rev 56

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 56 alirezamon
package Exporter::Tiny;
2
 
3
use 5.006001;
4
use strict;
5
use warnings; no warnings qw(void once uninitialized numeric redefine);
6
 
7
our $AUTHORITY = 'cpan:TOBYINK';
8
our $VERSION   = '1.002002';
9
our @EXPORT_OK = qw< mkopt mkopt_hash _croak _carp >;
10
 
11
sub _croak ($;@) { require Carp; my $fmt = shift; @_ = sprintf($fmt, @_); goto \&Carp::croak }
12
sub _carp  ($;@) { require Carp; my $fmt = shift; @_ = sprintf($fmt, @_); goto \&Carp::carp }
13
 
14
my $_process_optlist = sub
15
{
16
        my $class = shift;
17
        my ($global_opts, $opts, $want, $not_want) = @_;
18
 
19
        while (@$opts)
20
        {
21
                my $opt = shift @{$opts};
22
                my ($name, $value) = @$opt;
23
 
24
                ($name =~ m{\A\!(/.+/[msixpodual]*)\z}) ?
25
                        do {
26
                                my @not = $class->_exporter_expand_regexp($1, $value, $global_opts);
27
                                ++$not_want->{$_->[0]} for @not;
28
                        } :
29
                ($name =~ m{\A\!(.+)\z}) ?
30
                        (++$not_want->{$1}) :
31
                ($name =~ m{\A[:-](.+)\z}) ?
32
                        push(@$opts, $class->_exporter_expand_tag($1, $value, $global_opts)) :
33
                ($name =~ m{\A/.+/[msixpodual]*\z}) ?
34
                        push(@$opts, $class->_exporter_expand_regexp($name, $value, $global_opts)) :
35
                # else ?
36
                        push(@$want, $opt);
37
        }
38
};
39
 
40
sub import
41
{
42
        my $class = shift;
43
        my $global_opts = +{ @_ && ref($_[0]) eq q(HASH) ? %{+shift} : () };
44
        $global_opts->{into} = caller unless exists $global_opts->{into};
45
 
46
        my @want;
47
        my %not_want; $global_opts->{not} = \%not_want;
48
        my @args = do { no strict qw(refs); @_ ? @_ : @{"$class\::EXPORT"} };
49
        my $opts = mkopt(\@args);
50
        $class->$_process_optlist($global_opts, $opts, \@want, \%not_want);
51
 
52
        my $permitted = $class->_exporter_permitted_regexp($global_opts);
53
        $class->_exporter_validate_opts($global_opts);
54
 
55
        for my $wanted (@want)
56
        {
57
                next if $not_want{$wanted->[0]};
58
 
59
                my %symbols = $class->_exporter_expand_sub(@$wanted, $global_opts, $permitted);
60
                $class->_exporter_install_sub($_, $wanted->[1], $global_opts, $symbols{$_})
61
                        for keys %symbols;
62
        }
63
}
64
 
65
sub unimport
66
{
67
        my $class = shift;
68
        my $global_opts = +{ @_ && ref($_[0]) eq q(HASH) ? %{+shift} : () };
69
        $global_opts->{into} = caller unless exists $global_opts->{into};
70
        $global_opts->{is_unimport} = 1;
71
 
72
        my @want;
73
        my %not_want; $global_opts->{not} = \%not_want;
74
        my @args = do { our %TRACKED; @_ ? @_ : keys(%{$TRACKED{$class}{$global_opts->{into}}}) };
75
        my $opts = mkopt(\@args);
76
        $class->$_process_optlist($global_opts, $opts, \@want, \%not_want);
77
 
78
        my $permitted = $class->_exporter_permitted_regexp($global_opts);
79
        $class->_exporter_validate_unimport_opts($global_opts);
80
 
81
        my $expando = $class->can('_exporter_expand_sub');
82
        $expando = undef if $expando == \&_exporter_expand_sub;
83
 
84
        for my $wanted (@want)
85
        {
86
                next if $not_want{$wanted->[0]};
87
 
88
                if ($wanted->[1])
89
                {
90
                        _carp("Passing options to unimport '%s' makes no sense", $wanted->[0])
91
                                unless (ref($wanted->[1]) eq 'HASH' and not keys %{$wanted->[1]});
92
                }
93
 
94
                my %symbols = defined($expando)
95
                        ? $class->$expando(@$wanted, $global_opts, $permitted)
96
                        : ($wanted->[0] => sub { "dummy" });
97
                $class->_exporter_uninstall_sub($_, $wanted->[1], $global_opts)
98
                        for keys %symbols;
99
        }
100
}
101
 
102
# Called once per import/unimport, passed the "global" import options.
103
# Expected to validate the options and carp or croak if there are problems.
104
# Can also take the opportunity to do other stuff if needed.
105
#
106
sub _exporter_validate_opts          { 1 }
107
sub _exporter_validate_unimport_opts { 1 }
108
 
109
# Called after expanding a tag or regexp to merge the tag's options with
110
# any sub-specific options.
111
#
112
sub _exporter_merge_opts
113
{
114
        my $class = shift;
115
        my ($tag_opts, $global_opts, @stuff) = @_;
116
 
117
        $tag_opts = {} unless ref($tag_opts) eq q(HASH);
118
        _croak('Cannot provide an -as option for tags')
119
                if exists $tag_opts->{-as} && ref $tag_opts->{-as} ne 'CODE';
120
 
121
        my $optlist = mkopt(\@stuff);
122
        for my $export (@$optlist)
123
        {
124
                next if defined($export->[1]) && ref($export->[1]) ne q(HASH);
125
 
126
                my %sub_opts = ( %{ $export->[1] or {} }, %$tag_opts );
127
                $sub_opts{-prefix} = sprintf('%s%s', $tag_opts->{-prefix}, $export->[1]{-prefix})
128
                        if exists($export->[1]{-prefix}) && exists($tag_opts->{-prefix});
129
                $sub_opts{-suffix} = sprintf('%s%s', $export->[1]{-suffix}, $tag_opts->{-suffix})
130
                        if exists($export->[1]{-suffix}) && exists($tag_opts->{-suffix});
131
                $export->[1] = \%sub_opts;
132
        }
133
        return @$optlist;
134
}
135
 
136
# Given a tag name, looks it up in %EXPORT_TAGS and returns the list of
137
# associated functions. The default implementation magically handles tags
138
# "all" and "default". The default implementation interprets any undefined
139
# tags as being global options.
140
# 
141
sub _exporter_expand_tag
142
{
143
        no strict qw(refs);
144
 
145
        my $class = shift;
146
        my ($name, $value, $globals) = @_;
147
        my $tags  = \%{"$class\::EXPORT_TAGS"};
148
 
149
        return $class->_exporter_merge_opts($value, $globals, $tags->{$name}->($class, @_))
150
                if ref($tags->{$name}) eq q(CODE);
151
 
152
        return $class->_exporter_merge_opts($value, $globals, @{$tags->{$name}})
153
                if exists $tags->{$name};
154
 
155
        return $class->_exporter_merge_opts($value, $globals, @{"$class\::EXPORT"}, @{"$class\::EXPORT_OK"})
156
                if $name eq 'all';
157
 
158
        return $class->_exporter_merge_opts($value, $globals, @{"$class\::EXPORT"})
159
                if $name eq 'default';
160
 
161
        $globals->{$name} = $value || 1;
162
        return;
163
}
164
 
165
# Given a regexp-like string, looks it up in @EXPORT_OK and returns the
166
# list of matching functions.
167
# 
168
sub _exporter_expand_regexp
169
{
170
        no strict qw(refs);
171
        our %TRACKED;
172
 
173
        my $class = shift;
174
        my ($name, $value, $globals) = @_;
175
        my $compiled = eval("qr$name");
176
 
177
        my @possible = $globals->{is_unimport}
178
                ? keys( %{$TRACKED{$class}{$globals->{into}}} )
179
                : @{"$class\::EXPORT_OK"};
180
 
181
        $class->_exporter_merge_opts($value, $globals, grep /$compiled/, @possible);
182
}
183
 
184
# Helper for _exporter_expand_sub. Returns a regexp matching all subs in
185
# the exporter package which are available for export.
186
#
187
sub _exporter_permitted_regexp
188
{
189
        no strict qw(refs);
190
        my $class = shift;
191
        my $re = join "|", map quotemeta, sort {
192
                length($b) <=> length($a) or $a cmp $b
193
        } @{"$class\::EXPORT"}, @{"$class\::EXPORT_OK"};
194
        qr{^(?:$re)$}ms;
195
}
196
 
197
# Given a sub name, returns a hash of subs to install (usually just one sub).
198
# Keys are sub names, values are coderefs.
199
#
200
sub _exporter_expand_sub
201
{
202
        my $class = shift;
203
        my ($name, $value, $globals, $permitted) = @_;
204
        $permitted ||= $class->_exporter_permitted_regexp($globals);
205
 
206
        no strict qw(refs);
207
 
208
        my $sigil = "&";
209
        if ($name =~ /\A([&\$\%\@\*])(.+)\z/) {
210
                $sigil = $1;
211
                $name  = $2;
212
                if ($sigil eq '*') {
213
                        _croak("Cannot export symbols with a * sigil");
214
                }
215
        }
216
        my $sigilname = $sigil eq '&' ? $name : "$sigil$name";
217
 
218
        if ($sigilname =~ $permitted)
219
        {
220
                my $generatorprefix = {
221
                        '&' => "_generate_",
222
                        '$' => "_generateScalar_",
223
                        '@' => "_generateArray_",
224
                        '%' => "_generateHash_",
225
                }->{$sigil};
226
 
227
                my $generator = $class->can("$generatorprefix$name");
228
                return $sigilname => $class->$generator($sigilname, $value, $globals) if $generator;
229
 
230
                my $sub = $class->can($name);
231
                return $sigilname => $sub if $sub;
232
 
233
                # Could do this more cleverly, but this works.
234
                if ($sigil ne '&') {
235
                        my $evalled = eval "\\${sigil}${class}::${name}";
236
                        return $sigilname => $evalled if $evalled;
237
                }
238
        }
239
 
240
        $class->_exporter_fail(@_);
241
}
242
 
243
# Called by _exporter_expand_sub if it is unable to generate a key-value
244
# pair for a sub.
245
#
246
sub _exporter_fail
247
{
248
        my $class = shift;
249
        my ($name, $value, $globals) = @_;
250
        return if $globals->{is_unimport};
251
        _croak("Could not find sub '%s' exported by %s", $name, $class);
252
}
253
 
254
# Actually performs the installation of the sub into the target package. This
255
# also handles renaming the sub.
256
#
257
sub _exporter_install_sub
258
{
259
        my $class = shift;
260
        my ($name, $value, $globals, $sym) = @_;
261
 
262
        my $into      = $globals->{into};
263
        my $installer = $globals->{installer} || $globals->{exporter};
264
 
265
        $name =
266
                ref    $globals->{as} ? $globals->{as}->($name) :
267
                ref    $value->{-as}  ? $value->{-as}->($name) :
268
                exists $value->{-as}  ? $value->{-as} :
269
                $name;
270
 
271
        return unless defined $name;
272
 
273
        my $sigil = "&";
274
        unless (ref($name)) {
275
                if ($name =~ /\A([&\$\%\@\*])(.+)\z/) {
276
                        $sigil = $1;
277
                        $name  = $2;
278
                        if ($sigil eq '*') {
279
                                _croak("Cannot export symbols with a * sigil");
280
                        }
281
                }
282
                my ($prefix) = grep defined, $value->{-prefix}, $globals->{prefix}, q();
283
                my ($suffix) = grep defined, $value->{-suffix}, $globals->{suffix}, q();
284
                $name = "$prefix$name$suffix";
285
        }
286
 
287
        my $sigilname = $sigil eq '&' ? $name : "$sigil$name";
288
 
289
#       if ({qw/$ SCALAR @ ARRAY % HASH & CODE/}->{$sigil} ne ref($sym)) {
290
#               warn $sym;
291
#               warn $sigilname;
292
#               _croak("Reference type %s does not match sigil %s", ref($sym), $sigil);
293
#       }
294
 
295
        return ($$name = $sym)              if ref($name) eq q(SCALAR);
296
        return ($into->{$sigilname} = $sym) if ref($into) eq q(HASH);
297
 
298
        no strict qw(refs);
299
        our %TRACKED;
300
 
301
        if (ref($sym) eq 'CODE' and exists &{"$into\::$name"} and \&{"$into\::$name"} != $sym)
302
        {
303
                my ($level) = grep defined, $value->{-replace}, $globals->{replace}, q(0);
304
                my $action = {
305
                        carp     => \&_carp,
306
 
307
                        ''       => \&_carp,
308
                        warn     => \&_carp,
309
                        nonfatal => \&_carp,
310
                        croak    => \&_croak,
311
                        fatal    => \&_croak,
312
                        die      => \&_croak,
313
                }->{$level} || sub {};
314
 
315
                # Don't complain about double-installing the same sub. This isn't ideal
316
                # because the same named sub might be generated in two different ways.
317
                $action = sub {} if $TRACKED{$class}{$into}{$sigilname};
318
 
319
                $action->(
320
                        $action == \&_croak
321
                                ? "Refusing to overwrite existing sub '%s::%s' with sub '%s' exported by %s"
322
                                : "Overwriting existing sub '%s::%s' with sub '%s' exported by %s",
323
                        $into,
324
                        $name,
325
                        $_[0],
326
                        $class,
327
                );
328
        }
329
 
330
        $TRACKED{$class}{$into}{$sigilname} = $sym;
331
 
332
        no warnings qw(prototype);
333
        $installer
334
                ? $installer->($globals, [$sigilname, $sym])
335
                : (*{"$into\::$name"} = $sym);
336
}
337
 
338
sub _exporter_uninstall_sub
339
{
340
        our %TRACKED;
341
        my $class = shift;
342
        my ($name, $value, $globals, $sym) = @_;
343
        my $into = $globals->{into};
344
        ref $into and return;
345
 
346
        no strict qw(refs);
347
 
348
        my $sigil = "&";
349
        if ($name =~ /\A([&\$\%\@\*])(.+)\z/) {
350
                $sigil = $1;
351
                $name  = $2;
352
                if ($sigil eq '*') {
353
                        _croak("Cannot export symbols with a * sigil");
354
                }
355
        }
356
        my $sigilname = $sigil eq '&' ? $name : "$sigil$name";
357
 
358
        if ($sigil ne '&') {
359
                _croak("Unimporting non-code symbols not supported yet");
360
        }
361
 
362
        # Cowardly refuse to uninstall a sub that differs from the one
363
        # we installed!
364
        my $our_coderef = $TRACKED{$class}{$into}{$name};
365
        my $cur_coderef = exists(&{"$into\::$name"}) ? \&{"$into\::$name"} : -1;
366
        return unless $our_coderef == $cur_coderef;
367
 
368
        my $stash     = \%{"$into\::"};
369
        my $old       = delete $stash->{$name};
370
        my $full_name = join('::', $into, $name);
371
        foreach my $type (qw(SCALAR HASH ARRAY IO)) # everything but the CODE
372
        {
373
                next unless defined(*{$old}{$type});
374
                *$full_name = *{$old}{$type};
375
        }
376
 
377
        delete $TRACKED{$class}{$into}{$name};
378
}
379
 
380
sub mkopt
381
{
382
        my $in = shift or return [];
383
        my @out;
384
 
385
        $in = [map(($_ => ref($in->{$_}) ? $in->{$_} : ()), sort keys %$in)]
386
                if ref($in) eq q(HASH);
387
 
388
        for (my $i = 0; $i < @$in; $i++)
389
        {
390
                my $k = $in->[$i];
391
                my $v;
392
 
393
                ($i == $#$in)         ? ($v = undef) :
394
                !defined($in->[$i+1]) ? (++$i, ($v = undef)) :
395
                !ref($in->[$i+1])     ? ($v = undef) :
396
                ($v = $in->[++$i]);
397
 
398
                push @out, [ $k => $v ];
399
        }
400
 
401
        \@out;
402
}
403
 
404
sub mkopt_hash
405
{
406
        my $in  = shift or return;
407
        my %out = map +($_->[0] => $_->[1]), @{ mkopt($in) };
408
        \%out;
409
}
410
 
411
1;
412
 
413
__END__
414
 
415
=pod
416
 
417
=encoding utf-8
418
 
419
=for stopwords frobnicate greps regexps
420
 
421
=head1 NAME
422
 
423
Exporter::Tiny - an exporter with the features of Sub::Exporter but only core dependencies
424
 
425
=head1 SYNOPSIS
426
 
427
   package MyUtils;
428
   use base "Exporter::Tiny";
429
   our @EXPORT = qw(frobnicate);
430
   sub frobnicate { ... }
431
   1;
432
 
433
   package MyScript;
434
   use MyUtils "frobnicate" => { -as => "frob" };
435
   print frob(42);
436
   exit;
437
 
438
=head1 DESCRIPTION
439
 
440
Exporter::Tiny supports many of Sub::Exporter's external-facing features
441
including renaming imported functions with the C<< -as >>, C<< -prefix >> and
442
C<< -suffix >> options; explicit destinations with the C<< into >> option;
443
and alternative installers with the C<< installer >> option. But it's written
444
in only about 40% as many lines of code and with zero non-core dependencies.
445
 
446
Its internal-facing interface is closer to Exporter.pm, with configuration
447
done through the C<< @EXPORT >>, C<< @EXPORT_OK >> and C<< %EXPORT_TAGS >>
448
package variables.
449
 
450
If you are trying to B<write> a module that inherits from Exporter::Tiny,
451
then look at:
452
 
453
=over
454
 
455
=item *
456
 
457
L<Exporter::Tiny::Manual::QuickStart>
458
 
459
=item *
460
 
461
L<Exporter::Tiny::Manual::Exporting>
462
 
463
=back
464
 
465
If you are trying to B<use> a module that inherits from Exporter::Tiny,
466
then look at:
467
 
468
=over
469
 
470
=item *
471
 
472
L<Exporter::Tiny::Manual::Importing>
473
 
474
=back
475
 
476
=head1 BUGS
477
 
478
Please report any bugs to
479
L<http://rt.cpan.org/Dist/Display.html?Queue=Exporter-Tiny>.
480
 
481
=head1 SUPPORT
482
 
483
B<< IRC: >> support is available through in the I<< #moops >> channel
484
on L<irc.perl.org|http://www.irc.perl.org/channels.html>.
485
 
486
=head1 SEE ALSO
487
 
488
Simplified interface to this module: L<Exporter::Shiny>.
489
 
490
Other interesting exporters: L<Sub::Exporter>, L<Exporter>.
491
 
492
=head1 AUTHOR
493
 
494
Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
495
 
496
=head1 COPYRIGHT AND LICENCE
497
 
498
This software is copyright (c) 2013-2014, 2017 by Toby Inkster.
499
 
500
This is free software; you can redistribute it and/or modify it under
501
the same terms as the Perl 5 programming language system itself.
502
 
503
=head1 DISCLAIMER OF WARRANTIES
504
 
505
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
506
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
507
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
508
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.