182 lines
4.3 KiB
Perl
182 lines
4.3 KiB
Perl
package overload;
|
|
|
|
our $VERSION = '1.28';
|
|
|
|
%ops = (
|
|
with_assign => "+ - * / % ** << >> x .",
|
|
assign => "+= -= *= /= %= **= <<= >>= x= .=",
|
|
num_comparison => "< <= > >= == !=",
|
|
'3way_comparison' => "<=> cmp",
|
|
str_comparison => "lt le gt ge eq ne",
|
|
binary => '& &= | |= ^ ^= &. &.= |. |.= ^. ^.=',
|
|
unary => "neg ! ~ ~.",
|
|
mutators => '++ --',
|
|
func => "atan2 cos sin exp abs log sqrt int",
|
|
conversion => 'bool "" 0+ qr',
|
|
iterators => '<>',
|
|
filetest => "-X",
|
|
dereferencing => '${} @{} %{} &{} *{}',
|
|
matching => '~~',
|
|
special => 'nomethod fallback =',
|
|
);
|
|
|
|
my %ops_seen;
|
|
@ops_seen{ map split(/ /), values %ops } = ();
|
|
|
|
sub nil {}
|
|
|
|
sub OVERLOAD {
|
|
$package = shift;
|
|
my %arg = @_;
|
|
my $sub;
|
|
*{$package . "::(("} = \&nil; # Make it findable via fetchmethod.
|
|
for (keys %arg) {
|
|
if ($_ eq 'fallback') {
|
|
for my $sym (*{$package . "::()"}) {
|
|
*$sym = \&nil; # Make it findable via fetchmethod.
|
|
$$sym = $arg{$_};
|
|
}
|
|
} else {
|
|
warnings::warnif("overload arg '$_' is invalid")
|
|
unless exists $ops_seen{$_};
|
|
$sub = $arg{$_};
|
|
if (not ref $sub) {
|
|
$ {$package . "::(" . $_} = $sub;
|
|
$sub = \&nil;
|
|
}
|
|
#print STDERR "Setting '$ {'package'}::\cO$_' to \\&'$sub'.\n";
|
|
*{$package . "::(" . $_} = \&{ $sub };
|
|
}
|
|
}
|
|
}
|
|
|
|
sub import {
|
|
$package = (caller())[0];
|
|
# *{$package . "::OVERLOAD"} = \&OVERLOAD;
|
|
shift;
|
|
$package->overload::OVERLOAD(@_);
|
|
}
|
|
|
|
sub unimport {
|
|
$package = (caller())[0];
|
|
shift;
|
|
*{$package . "::(("} = \&nil;
|
|
for (@_) {
|
|
warnings::warnif("overload arg '$_' is invalid")
|
|
unless exists $ops_seen{$_};
|
|
delete $ {$package . "::"}{$_ eq 'fallback' ? '()' : "(" .$_};
|
|
}
|
|
}
|
|
|
|
sub Overloaded {
|
|
my $package = shift;
|
|
$package = ref $package if ref $package;
|
|
mycan ($package, '()') || mycan ($package, '((');
|
|
}
|
|
|
|
sub ov_method {
|
|
my $globref = shift;
|
|
return undef unless $globref;
|
|
my $sub = \&{*$globref};
|
|
no overloading;
|
|
return $sub if $sub != \&nil;
|
|
return shift->can($ {*$globref});
|
|
}
|
|
|
|
sub OverloadedStringify {
|
|
my $package = shift;
|
|
$package = ref $package if ref $package;
|
|
#$package->can('(""')
|
|
ov_method mycan($package, '(""'), $package
|
|
or ov_method mycan($package, '(0+'), $package
|
|
or ov_method mycan($package, '(bool'), $package
|
|
or ov_method mycan($package, '(nomethod'), $package;
|
|
}
|
|
|
|
sub Method {
|
|
my $package = shift;
|
|
if(ref $package) {
|
|
local $@;
|
|
local $!;
|
|
require Scalar::Util;
|
|
$package = Scalar::Util::blessed($package);
|
|
return undef if !defined $package;
|
|
}
|
|
#my $meth = $package->can('(' . shift);
|
|
ov_method mycan($package, '(' . shift), $package;
|
|
#return $meth if $meth ne \&nil;
|
|
#return $ {*{$meth}};
|
|
}
|
|
|
|
sub AddrRef {
|
|
no overloading;
|
|
"$_[0]";
|
|
}
|
|
|
|
*StrVal = *AddrRef;
|
|
|
|
sub mycan { # Real can would leave stubs.
|
|
my ($package, $meth) = @_;
|
|
|
|
local $@;
|
|
local $!;
|
|
require mro;
|
|
|
|
my $mro = mro::get_linear_isa($package);
|
|
foreach my $p (@$mro) {
|
|
my $fqmeth = $p . q{::} . $meth;
|
|
return \*{$fqmeth} if defined &{$fqmeth};
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
|
|
%constants = (
|
|
'integer' => 0x1000, # HINT_NEW_INTEGER
|
|
'float' => 0x2000, # HINT_NEW_FLOAT
|
|
'binary' => 0x4000, # HINT_NEW_BINARY
|
|
'q' => 0x8000, # HINT_NEW_STRING
|
|
'qr' => 0x10000, # HINT_NEW_RE
|
|
);
|
|
|
|
use warnings::register;
|
|
sub constant {
|
|
# Arguments: what, sub
|
|
while (@_) {
|
|
if (@_ == 1) {
|
|
warnings::warnif ("Odd number of arguments for overload::constant");
|
|
last;
|
|
}
|
|
elsif (!exists $constants {$_ [0]}) {
|
|
warnings::warnif ("'$_[0]' is not an overloadable type");
|
|
}
|
|
elsif (!ref $_ [1] || "$_[1]" !~ /(^|=)CODE\(0x[0-9a-f]+\)$/) {
|
|
# Can't use C<ref $_[1] eq "CODE"> above as code references can be
|
|
# blessed, and C<ref> would return the package the ref is blessed into.
|
|
if (warnings::enabled) {
|
|
$_ [1] = "undef" unless defined $_ [1];
|
|
warnings::warn ("'$_[1]' is not a code reference");
|
|
}
|
|
}
|
|
else {
|
|
$^H{$_[0]} = $_[1];
|
|
$^H |= $constants{$_[0]};
|
|
}
|
|
shift, shift;
|
|
}
|
|
}
|
|
|
|
sub remove_constant {
|
|
# Arguments: what, sub
|
|
while (@_) {
|
|
delete $^H{$_[0]};
|
|
$^H &= ~ $constants{$_[0]};
|
|
shift, shift;
|
|
}
|
|
}
|
|
|
|
1;
|
|
|
|
__END__
|
|
|