line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Sub::Signatures; |
2
|
|
|
|
|
|
|
$REVISION = '$Id: Signatures.pm,v 1.3 2004/12/05 21:19:33 ovid Exp $'; |
3
|
|
|
|
|
|
|
$VERSION = '0.21'; |
4
|
|
|
|
|
|
|
|
5
|
10
|
|
|
10
|
|
306936
|
use 5.006; |
|
10
|
|
|
|
|
39
|
|
|
10
|
|
|
|
|
483
|
|
6
|
10
|
|
|
10
|
|
85
|
use strict; |
|
10
|
|
|
|
|
27
|
|
|
10
|
|
|
|
|
383
|
|
7
|
10
|
|
|
10
|
|
58
|
use warnings; |
|
10
|
|
|
|
|
21
|
|
|
10
|
|
|
|
|
323
|
|
8
|
10
|
|
|
10
|
|
12001
|
use Filter::Simple; |
|
10
|
|
|
|
|
337040
|
|
|
10
|
|
|
|
|
86
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
my $CALLPACK; |
11
|
|
|
|
|
|
|
my %SIG; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
my %METHODS; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub import { |
16
|
|
|
|
|
|
|
my $class = shift; |
17
|
|
|
|
|
|
|
my %props = map { $_ => 1 } @_; |
18
|
|
|
|
|
|
|
($CALLPACK) = caller; |
19
|
|
|
|
|
|
|
$METHODS{$CALLPACK} = exists $props{methods} ? 1 : 0; |
20
|
|
|
|
|
|
|
if ( $ENV{SS_DEBUG} ) { |
21
|
|
|
|
|
|
|
require Data::Dumper; |
22
|
|
|
|
|
|
|
Data::Dumper->import; |
23
|
|
|
|
|
|
|
$Data::Dumper::Indent = 1; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
my $signature = sub { |
28
|
|
|
|
|
|
|
my ( $subname, $parameters ) = @_; |
29
|
|
|
|
|
|
|
if ( 'fallback' eq $parameters ) { |
30
|
|
|
|
|
|
|
return ( "_${subname}_fallback", '', 0 ); |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
else { |
33
|
|
|
|
|
|
|
my @args = |
34
|
|
|
|
|
|
|
map { /\s*(\S*)\s*(\$\w+)/; [ $1 || 'SCALAR', $2 ] } |
35
|
|
|
|
|
|
|
split /(?:,|=>)/ => $parameters; |
36
|
|
|
|
|
|
|
my $count = @args; |
37
|
|
|
|
|
|
|
$parameters = join ', ' => map { $_->[1] } @args; |
38
|
|
|
|
|
|
|
return ( "__${subname}_$count", $parameters, scalar @args ); |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
}; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my $make_subs = sub { |
43
|
|
|
|
|
|
|
while ( my ( $pack, $subs ) = each %SIG ) { |
44
|
|
|
|
|
|
|
while ( my ( $sub, $counts ) = each %$subs ) { |
45
|
|
|
|
|
|
|
my @build = |
46
|
|
|
|
|
|
|
sort { $a->[1] cmp $b->[1] } |
47
|
|
|
|
|
|
|
map { [ $_ => $counts->{$_} ] } keys %$counts; |
48
|
|
|
|
|
|
|
foreach my $item (@build) { |
49
|
|
|
|
|
|
|
my ( $count, $target ) = @$item; |
50
|
|
|
|
|
|
|
next if 0 <= index +( $subs->{$sub}{body} || '' ), $target; |
51
|
|
|
|
|
|
|
next if 'body' eq $count; |
52
|
|
|
|
|
|
|
$subs->{$sub}{body} ||= ''; |
53
|
|
|
|
|
|
|
$subs->{$sub}{body} .= $target =~ /_fallback$/ |
54
|
|
|
|
|
|
|
? " goto \&$target;\n" |
55
|
|
|
|
|
|
|
: " goto \&$target if $count == \@_;\n"; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
print Dumper(%SIG) if $ENV{SS_DEBUG}; |
60
|
|
|
|
|
|
|
}; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
my $install_subs = sub { |
63
|
|
|
|
|
|
|
while ( my ( $pack, $subs ) = each %SIG ) { |
64
|
|
|
|
|
|
|
foreach my $sub ( keys %$subs ) { |
65
|
|
|
|
|
|
|
my $body = $subs->{$sub}{body}; |
66
|
|
|
|
|
|
|
my $type = $METHODS{$pack} ? 'method' : 'sub'; |
67
|
|
|
|
|
|
|
unless ( $body =~ /_fallback;/ ) { |
68
|
|
|
|
|
|
|
$body .= <<" END_BODY"; |
69
|
|
|
|
|
|
|
# if we got to here, there was no $type to dispatch to |
70
|
|
|
|
|
|
|
require Carp; |
71
|
|
|
|
|
|
|
shift if 'method' eq '$type'; |
72
|
|
|
|
|
|
|
my \$types = join ', ' => map { ref \$_ || 'SCALAR' } \@_; |
73
|
|
|
|
|
|
|
Carp::croak "Could not find a $type matching your signature: $sub(\$types)"; |
74
|
|
|
|
|
|
|
END_BODY |
75
|
|
|
|
|
|
|
} |
76
|
10
|
|
|
10
|
|
8469
|
no warnings 'redefine'; |
|
10
|
|
|
|
|
21
|
|
|
10
|
|
|
|
|
8475
|
|
77
|
|
|
|
|
|
|
my $installed_sub = "package $pack;\nsub $sub {\n$body}"; |
78
|
18
|
100
|
|
18
|
0
|
18921
|
eval $installed_sub; |
|
7
|
100
|
|
2
|
0
|
45
|
|
|
2
|
0
|
|
11
|
0
|
8
|
|
|
1
|
100
|
|
2
|
|
3
|
|
|
2
|
50
|
|
3
|
|
13
|
|
|
1
|
100
|
|
|
|
27
|
|
|
0
|
100
|
|
|
|
0
|
|
|
2
|
50
|
|
|
|
683
|
|
|
1
|
50
|
|
|
|
8
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
7
|
|
|
|
|
4325
|
|
|
10
|
|
|
|
|
4773
|
|
|
1
|
|
|
|
|
6
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
819
|
|
|
1
|
|
|
|
|
730
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
2
|
|
|
|
|
1399
|
|
|
1
|
|
|
|
|
435
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
warn |
80
|
|
|
|
|
|
|
"Installing &${pack}::$sub\n----------\n$installed_sub\n----------\n" |
81
|
|
|
|
|
|
|
if !$@ && $ENV{SS_DEBUG}; |
82
|
|
|
|
|
|
|
die |
83
|
|
|
|
|
|
|
"Failed to install &${pack}::$sub\n----------\n$installed_sub\n----------\nReason: $@" |
84
|
|
|
|
|
|
|
if $@; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
}; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# each regex can capture itself! |
90
|
|
|
|
|
|
|
my $sub_name_re = qr/([_[:alpha:]][[:word:]]*)/; |
91
|
|
|
|
|
|
|
my $parameters_re = qr/\(([^)]+)\)/; |
92
|
|
|
|
|
|
|
FILTER { |
93
|
|
|
|
|
|
|
warn "Calling package: $CALLPACK ****" if $ENV{SS_DEBUG}; |
94
|
|
|
|
|
|
|
while (/(sub\s+$sub_name_re?\s*$parameters_re[^{]*\{)/) { |
95
|
|
|
|
|
|
|
my ( $sub_with_sig, $oldname, $parameters ) = ( $1, $2, $3 ); |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# the following line doesn't work. For some reason, using prototypes |
98
|
|
|
|
|
|
|
# with this module causes an infinite while loop here. |
99
|
|
|
|
|
|
|
# I'm probably overlooking something really obvious. |
100
|
|
|
|
|
|
|
# next if $parameters =~ /^\s*[\\\$@%*;\[\]]*\s*$/; # ignore prototypes |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
my ( $newname, $newparams, $count ); |
103
|
|
|
|
|
|
|
if ($oldname) { |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# named sub |
106
|
|
|
|
|
|
|
( $newname, $newparams, $count ) = |
107
|
|
|
|
|
|
|
$signature->( $oldname, $parameters ); |
108
|
|
|
|
|
|
|
if ( exists $SIG{$CALLPACK}{$oldname} |
109
|
|
|
|
|
|
|
&& exists $SIG{$CALLPACK}{$oldname}{$count} ) |
110
|
|
|
|
|
|
|
{ |
111
|
|
|
|
|
|
|
my $args = $newname; |
112
|
|
|
|
|
|
|
$args =~ s/^_\w+_//; |
113
|
|
|
|
|
|
|
$args =~ s/_/, /g; |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# how do I get the line number? |
116
|
|
|
|
|
|
|
die "$oldname($args) redefined in package '$CALLPACK'"; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
$SIG{$CALLPACK}{$oldname}{$count} = $newname; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
else { |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# anonymous sub |
123
|
|
|
|
|
|
|
$newname = ''; |
124
|
|
|
|
|
|
|
$newparams = $parameters; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
if ($newparams) { |
127
|
|
|
|
|
|
|
s/\Q$sub_with_sig\E/sub $newname \{ my ($newparams) = \@_;/; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
else { |
130
|
|
|
|
|
|
|
s/\Q$sub_with_sig\E/sub $newname \{/; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
$make_subs->(); |
134
|
|
|
|
|
|
|
$install_subs->(); |
135
|
|
|
|
|
|
|
print $_ if $ENV{SS_DEBUG}; |
136
|
|
|
|
|
|
|
}; |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
1; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
__END__ |