blob: 02fa01e339f4718a064f9c6fc194c132e0de89e9 [file] [log] [blame]
Rashed Abdel-Tawab4db47f42019-09-06 10:38:22 -07001package attributes;
2
3our $VERSION = 0.29;
4
5@EXPORT_OK = qw(get reftype);
6@EXPORT = ();
7%EXPORT_TAGS = (ALL => [@EXPORT, @EXPORT_OK]);
8
9use strict;
10
11sub croak {
12 require Carp;
13 goto &Carp::croak;
14}
15
16sub carp {
17 require Carp;
18 goto &Carp::carp;
19}
20
21my %deprecated;
22$deprecated{CODE} = qr/\A-?(locked)\z/;
23$deprecated{ARRAY} = $deprecated{HASH} = $deprecated{SCALAR}
24 = qr/\A-?(unique)\z/;
25
26my %msg = (
27 lvalue => 'lvalue attribute applied to already-defined subroutine',
28 -lvalue => 'lvalue attribute removed from already-defined subroutine',
29 const => 'Useless use of attribute "const"',
30);
31
32sub _modify_attrs_and_deprecate {
33 my $svtype = shift;
34 # Now that we've removed handling of locked from the XS code, we need to
35 # remove it here, else it ends up in @badattrs. (If we do the deprecation in
36 # XS, we can't control the warning based on *our* caller's lexical settings,
37 # and the warned line is in this package)
38 grep {
39 $deprecated{$svtype} && /$deprecated{$svtype}/ ? do {
40 require warnings;
41 warnings::warnif('deprecated', "Attribute \"$1\" is deprecated, " .
42 "and will disappear in Perl 5.28");
43 0;
44 } : $svtype eq 'CODE' && exists $msg{$_} ? do {
45 require warnings;
46 warnings::warnif(
47 'misc',
48 $msg{$_}
49 );
50 0;
51 } : 1
52 } _modify_attrs(@_);
53}
54
55sub import {
56 @_ > 2 && ref $_[2] or do {
57 require Exporter;
58 goto &Exporter::import;
59 };
60 my (undef,$home_stash,$svref,@attrs) = @_;
61
62 my $svtype = uc reftype($svref);
63 my $pkgmeth;
64 $pkgmeth = UNIVERSAL::can($home_stash, "MODIFY_${svtype}_ATTRIBUTES")
65 if defined $home_stash && $home_stash ne '';
66 my @badattrs;
67 if ($pkgmeth) {
68 my @pkgattrs = _modify_attrs_and_deprecate($svtype, $svref, @attrs);
69 @badattrs = $pkgmeth->($home_stash, $svref, @pkgattrs);
70 if (!@badattrs && @pkgattrs) {
71 require warnings;
72 return unless warnings::enabled('reserved');
73 @pkgattrs = grep { m/\A[[:lower:]]+(?:\z|\()/ } @pkgattrs;
74 if (@pkgattrs) {
75 for my $attr (@pkgattrs) {
76 $attr =~ s/\(.+\z//s;
77 }
78 my $s = ((@pkgattrs == 1) ? '' : 's');
79 carp "$svtype package attribute$s " .
80 "may clash with future reserved word$s: " .
81 join(' : ' , @pkgattrs);
82 }
83 }
84 }
85 else {
86 @badattrs = _modify_attrs_and_deprecate($svtype, $svref, @attrs);
87 }
88 if (@badattrs) {
89 croak "Invalid $svtype attribute" .
90 (( @badattrs == 1 ) ? '' : 's') .
91 ": " .
92 join(' : ', @badattrs);
93 }
94}
95
96sub get ($) {
97 @_ == 1 && ref $_[0] or
98 croak 'Usage: '.__PACKAGE__.'::get $ref';
99 my $svref = shift;
100 my $svtype = uc reftype($svref);
101 my $stash = _guess_stash($svref);
102 $stash = caller unless defined $stash;
103 my $pkgmeth;
104 $pkgmeth = UNIVERSAL::can($stash, "FETCH_${svtype}_ATTRIBUTES")
105 if defined $stash && $stash ne '';
106 return $pkgmeth ?
107 (_fetch_attrs($svref), $pkgmeth->($stash, $svref)) :
108 (_fetch_attrs($svref))
109 ;
110}
111
112sub require_version { goto &UNIVERSAL::VERSION }
113
114require XSLoader;
115XSLoader::load();
116
1171;
118__END__
119#The POD goes here
120