summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGurusamy Sarathy <gsar@cpan.org>1998-08-08 22:18:54 +0000
committerGurusamy Sarathy <gsar@cpan.org>1998-08-08 22:18:54 +0000
commit84df6dbaac5dcce30923bafc61c52f3ffa1b669b (patch)
treecf12e2c57eeb3ade406af6984e8a91a4ea05a830 /lib
parent527cc686938e627799b4befb57128e2e7c3272c2 (diff)
parent1eccc87f4ae921520ce1893dd988f4a8a1fa061d (diff)
downloadperl-84df6dbaac5dcce30923bafc61c52f3ffa1b669b.tar.gz
integrate maint-5.005 changes into mainline
p4raw-id: //depot/perl@1760
Diffstat (limited to 'lib')
-rw-r--r--lib/Benchmark.pm22
-rw-r--r--lib/Class/Struct.pm5
-rw-r--r--lib/ExtUtils/Liblist.pm205
-rw-r--r--lib/ExtUtils/MM_Win32.pm45
-rw-r--r--lib/File/DosGlob.pm23
-rw-r--r--lib/Math/Complex.pm156
-rw-r--r--lib/Pod/Html.pm2
-rw-r--r--lib/Test.pm2
-rw-r--r--lib/Test/Harness.pm28
-rw-r--r--lib/bigint.pl2
-rw-r--r--lib/dumpvar.pl13
-rw-r--r--lib/overload.pm543
-rw-r--r--lib/perl5db.pl7
13 files changed, 884 insertions, 169 deletions
diff --git a/lib/Benchmark.pm b/lib/Benchmark.pm
index f490998039..a28f510d11 100644
--- a/lib/Benchmark.pm
+++ b/lib/Benchmark.pm
@@ -238,6 +238,13 @@ functionality.
=cut
+# evaluate something in a clean lexical environment
+sub _doeval { eval shift }
+
+#
+# put any lexicals at file scope AFTER here
+#
+
use Carp;
use Exporter;
@ISA=(Exporter);
@@ -280,7 +287,7 @@ sub real { my($r,$pu,$ps,$cu,$cs) = @{$_[0]}; $r ; }
sub timediff {
my($a, $b) = @_;
my @r;
- for ($i=0; $i < @$a; ++$i) {
+ for (my $i=0; $i < @$a; ++$i) {
push(@r, $a->[$i] - $b->[$i]);
}
bless \@r;
@@ -329,10 +336,15 @@ sub runloop {
last if $pack ne $curpack;
}
- my $subcode = (ref $c eq 'CODE')
- ? "sub { package $pack; my(\$_i)=$n; while (\$_i--){&\$c;} }"
- : "sub { package $pack; my(\$_i)=$n; while (\$_i--){$c;} }";
- my $subref = eval $subcode;
+ my ($subcode, $subref);
+ if (ref $c eq 'CODE') {
+ $subcode = "sub { for (1 .. $n) { local \$_; package $pack; &\$c; } }";
+ $subref = eval $subcode;
+ }
+ else {
+ $subcode = "sub { for (1 .. $n) { local \$_; package $pack; $c;} }";
+ $subref = _doeval($subcode);
+ }
croak "runloop unable to compile '$c': $@\ncode: $subcode\n" if $@;
print STDERR "runloop $n '$subcode'\n" if $debug;
diff --git a/lib/Class/Struct.pm b/lib/Class/Struct.pm
index a39d1ac04a..8fddfbf68e 100644
--- a/lib/Class/Struct.pm
+++ b/lib/Class/Struct.pm
@@ -40,6 +40,11 @@ sub printem {
$self->[$index];
}
+ sub FETCHSIZE {
+ my $self = shift;
+ return scalar(@$self);
+ }
+
sub DESTROY { }
}
diff --git a/lib/ExtUtils/Liblist.pm b/lib/ExtUtils/Liblist.pm
index 94f36018e2..b072c1292c 100644
--- a/lib/ExtUtils/Liblist.pm
+++ b/lib/ExtUtils/Liblist.pm
@@ -191,10 +191,14 @@ sub _win32_ext {
# (caller should probably use the list in $Config{libs})
return ("", "", "", "") unless $potential_libs;
- my($so) = $Config{'so'};
- my($libs) = $Config{'libs'};
- my($libpth) = $Config{'libpth'};
- my($libext) = $Config{'lib_ext'} || ".lib";
+ my $cc = $Config{cc};
+ my $VC = 1 if $cc =~ /^cl/i;
+ my $BC = 1 if $cc =~ /^bcc/i;
+ my $GC = 1 if $cc =~ /^gcc/i;
+ my $so = $Config{'so'};
+ my $libs = $Config{'libs'};
+ my $libpth = $Config{'libpth'};
+ my $libext = $Config{'lib_ext'} || ".lib";
if ($libs and $potential_libs !~ /:nodefault/i) {
# If Config.pm defines a set of default libs, we always
@@ -212,61 +216,100 @@ sub _win32_ext {
# compute $extralibs from $potential_libs
- my(@searchpath); # from "-L/path" entries in $potential_libs
- my(@libpath) = Text::ParseWords::quotewords('\s+', 0, $libpth);
- my(@extralibs);
+ my @searchpath; # from "-L/path" in $potential_libs
+ my @libpath = Text::ParseWords::quotewords('\s+', 0, $libpth);
+ my @extralibs;
+ my $pwd = cwd(); # from Cwd.pm
+ my $lib = '';
+ my $found = 0;
+ my $search = 1;
my($fullname, $thislib, $thispth);
- my($pwd) = cwd(); # from Cwd.pm
- my($lib) = '';
- my($found) = 0;
- foreach $thislib (Text::ParseWords::quotewords('\s+', 0, $potential_libs)){
+ foreach (Text::ParseWords::quotewords('\s+', 0, $potential_libs)){
- # Handle possible linker path arguments.
- if ($thislib =~ s/^-L// and not -d $thislib) {
- warn "-L$thislib ignored, directory does not exist\n"
+ $thislib = $_;
+
+ # see if entry is a flag
+ if (/^:\w+$/) {
+ $search = 0 if lc eq ':nosearch';
+ $search = 1 if lc eq ':search';
+ warn "Ignoring unknown flag '$thislib'\n"
+ if $verbose and !/^:(no)?(search|default)$/i;
+ next;
+ }
+
+ # if searching is disabled, do compiler-specific translations
+ unless ($search) {
+ s/^-L/-libpath:/ if $VC;
+ s/^-l(.+)$/$1.lib/ unless $GC;
+ push(@extralibs, $_);
+ $found++;
+ next;
+ }
+
+ # handle possible linker path arguments
+ if (s/^-L// and not -d) {
+ warn "$thislib ignored, directory does not exist\n"
if $verbose;
next;
}
- elsif (-d $thislib) {
- unless ($self->file_name_is_absolute($thislib)) {
- warn "Warning: '-L$thislib' changed to '-L$pwd/$thislib'\n";
- $thislib = $self->catdir($pwd,$thislib);
+ elsif (-d) {
+ unless ($self->file_name_is_absolute($_)) {
+ warn "Warning: '$thislib' changed to '-L$pwd/$_'\n";
+ $_ = $self->catdir($pwd,$_);
}
- push(@searchpath, $thislib);
+ push(@searchpath, $_);
next;
}
- # Handle possible library arguments.
- if ($thislib =~ s/^-l// and $thislib !~ /^lib/i) {
- $thislib = "lib$thislib";
+ # handle possible library arguments
+ if (s/^-l// and $GC and !/^lib/i) {
+ $_ = "lib$_";
}
- $thislib .= $libext if $thislib !~ /\Q$libext\E$/i;
+ $_ .= $libext if !/\Q$libext\E$/i;
+
+ my $secondpass = 0;
+ LOOKAGAIN:
# look for the file itself
- if (-f $thislib) {
- warn "'$thislib' found\n" if $verbose;
+ if (-f) {
+ warn "'$thislib' found as '$_'\n" if $verbose;
$found++;
- push(@extralibs, $thislib);
+ push(@extralibs, $_);
next;
}
- my($found_lib)=0;
+ my $found_lib = 0;
foreach $thispth (@searchpath, @libpath){
- unless (-f ($fullname="$thispth\\$thislib")) {
- warn "$thislib not found in $thispth\n" if $verbose;
+ unless (-f ($fullname="$thispth\\$_")) {
+ warn "'$thislib' not found as '$fullname'\n" if $verbose;
next;
}
- warn "'$thislib' found at $fullname\n" if $verbose;
+ warn "'$thislib' found as '$fullname'\n" if $verbose;
$found++;
$found_lib++;
push(@extralibs, $fullname);
last;
}
+
+ # do another pass with (or without) leading 'lib' if they used -l
+ if (!$found_lib and $thislib =~ /^-l/ and !$secondpass++) {
+ if ($GC) {
+ goto LOOKAGAIN if s/^lib//i;
+ }
+ elsif (!/^lib/i) {
+ $_ = "lib$_";
+ goto LOOKAGAIN;
+ }
+ }
+
+ # give up
warn "Note (probably harmless): "
."No library found for '$thislib'\n"
unless $found_lib>0;
+
}
+
return ('','','','') unless $found;
# make sure paths with spaces are properly quoted
@@ -579,16 +622,38 @@ Unix-OS/2 version in several respects:
=item *
+If C<$potential_libs> is empty, the return value will be empty.
+Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm)
+will be appended to the list of C<$potential_libs>. The libraries
+will be searched for in the directories specified in C<$potential_libs>
+as well as in C<$Config{libpth}>. For each library that is found, a
+space-separated list of fully qualified library pathnames is generated.
+
+=item *
+
Input library and path specifications are accepted with or without the
-C<-l> and C<-L> prefices used by Unix linkers. C<-lfoo> specifies the
-library C<libfoo.lib> (unless C<foo> already starts with C<lib>), and
-C<-Ls:ome\dir> specifies a directory to look for the libraries that follow.
-If neither prefix is present, a token is considered a directory to search
-if it is in fact a directory, and a library to search for otherwise. The
-C<$Config{lib_ext}> suffix will be appended to any entries that are not
-directories and don't already have the suffix. Authors who wish their
-extensions to be portable to Unix or OS/2 should use the Unix prefixes,
-since the Unix-OS/2 version of ext() requires them.
+C<-l> and C<-L> prefices used by Unix linkers.
+
+An entry of the form C<-La:\foo> specifies the C<a:\foo> directory to look
+for the libraries that follow.
+
+An entry of the form C<-lfoo> specifies the library C<foo>, which may be
+spelled differently depending on what kind of compiler you are using. If
+you are using GCC, it gets translated to C<libfoo.a>, but for other win32
+compilers, it becomes C<foo.lib>. If no files are found by those translated
+names, one more attempt is made to find them using either C<foo.a> or
+C<libfoo.lib>, depending on whether GCC or some other win32 compiler is
+being used, respectively.
+
+If neither the C<-L> or C<-l> prefix is present in an entry, the entry is
+considered a directory to search if it is in fact a directory, and a
+library to search for otherwise. The C<$Config{lib_ext}> suffix will
+be appended to any entries that are not directories and don't already have
+the suffix.
+
+Note that the C<-L> and <-l> prefixes are B<not required>, but authors
+who wish their extensions to be portable to Unix or OS/2 should use the
+prefixes, since the Unix-OS/2 version of ext() requires them.
=item *
@@ -597,15 +662,21 @@ not handle object files in the place of libraries.
=item *
-If C<$potential_libs> is empty, the return value will be empty.
-Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm)
-will be appended to the list of C<$potential_libs>. The libraries
-will be searched for in the directories specified in C<$potential_libs>
-as well as in C<$Config{libpth}>. For each library that is found, a
-space-separated list of fully qualified library pathnames is generated.
-You may specify an entry that matches C</:nodefault/i> in
-C<$potential_libs> to disable the appending of default libraries
-found in C<$Config{libs}> (this should be only needed very rarely).
+Entries in C<$potential_libs> beginning with a colon and followed by
+alphanumeric characters are treated as flags. Unknown flags will be ignored.
+
+An entry that matches C</:nodefault/i> disables the appending of default
+libraries found in C<$Config{libs}> (this should be only needed very rarely).
+
+An entry that matches C</:nosearch/i> disables all searching for
+the libraries specified after it. Translation of C<-Lfoo> and
+C<-lfoo> still happens as appropriate (depending on compiler being used,
+as reflected by C<$Config{cc}>), but the entries are not verified to be
+valid files or directories.
+
+An entry that matches C</:search/i> reenables searching for
+the libraries specified after it. You can put it at the end to
+enable searching for default libraries specified by C<$Config{libs}>.
=item *
@@ -630,6 +701,44 @@ C<$potential_libs> could be (literally):
Note how the first and last entries are protected by quotes in order
to protect the spaces.
+=item *
+
+Since this module is most often used only indirectly from extension
+C<Makefile.PL> files, here is an example C<Makefile.PL> entry to add
+a library to the build process for an extension:
+
+ LIBS => ['-lgl']
+
+When using GCC, that entry specifies that MakeMaker should first look
+for C<libgl.a> (followed by C<gl.a>) in all the locations specified by
+C<$Config{libpth}>.
+
+When using a compiler other than GCC, the above entry will search for
+C<gl.lib> (followed by C<libgl.lib>).
+
+If the library happens to be in a location not in C<$Config{libpth}>,
+you need:
+
+ LIBS => ['-Lc:\gllibs -lgl']
+
+Here is a less often used example:
+
+ LIBS => ['-lgl', ':nosearch -Ld:\mesalibs -lmesa -luser32']
+
+This specifies a search for library C<gl> as before. If that search
+fails to find the library, it looks at the next item in the list. The
+C<:nosearch> flag will prevent searching for the libraries that follow,
+so it simply returns the value as C<-Ld:\mesalibs -lmesa -luser32>,
+since GCC can use that value as is with its linker.
+
+When using the Visual C compiler, the second item is returned as
+C<-libpath:d:\mesalibs mesa.lib user32.lib>.
+
+When using the Borland compiler, the second item is returned as
+C<-Ld:\mesalibs mesa.lib user32.lib>, and MakeMaker takes care of
+moving the C<-Ld:\mesalibs> to the correct place in the linker
+command line.
+
=back
diff --git a/lib/ExtUtils/MM_Win32.pm b/lib/ExtUtils/MM_Win32.pm
index 72c32fb195..a1226b5463 100644
--- a/lib/ExtUtils/MM_Win32.pm
+++ b/lib/ExtUtils/MM_Win32.pm
@@ -67,7 +67,21 @@ sub replace_manpage_separator {
sub maybe_command {
my($self,$file) = @_;
- return "$file.exe" if -e "$file.exe";
+ my @e = exists($ENV{'PATHEXT'})
+ ? split(/;/, $ENV{PATHEXT})
+ : qw(.com .exe .bat .cmd);
+ my $e = '';
+ for (@e) { $e .= "\Q$_\E|" }
+ chop $e;
+ # see if file ends in one of the known extensions
+ if ($file =~ /($e)$/i) {
+ return $file if -e $file;
+ }
+ else {
+ for (@e) {
+ return "$file$_" if -e "$file$_";
+ }
+ }
return;
}
@@ -155,21 +169,19 @@ sub init_others
$self->{'TEST_F'} = '$(PERL) -I$(PERL_ARCHLIB) -I$(PERL_LIB) -MExtUtils::Command -e test_f';
$self->{'LD'} = $Config{'ld'} || 'link';
$self->{'AR'} = $Config{'ar'} || 'lib';
- if ($GCC)
- {
- $self->{'LDLOADLIBS'} ||= ' ';
- }
- else
- {
- $self->{'LDLOADLIBS'}
- ||= ( $BORLAND
- ? 'import32.lib'
- : # compiler adds msvcrtd?.lib according to debug switches
- 'oldnames.lib kernel32.lib comdlg32.lib winspool.lib gdi32.lib '
- .'advapi32.lib user32.lib shell32.lib netapi32.lib ole32.lib '
- .'oleaut32.lib uuid.lib wsock32.lib mpr.lib winmm.lib version.lib'
- ) . ' $(LIBC) odbc32.lib odbccp32.lib';
- }
+ $self->{'LDLOADLIBS'} ||= $Config{'libs'};
+ # -Lfoo must come first for Borland, so we put it in LDDLFLAGS
+ if ($BORLAND) {
+ my $libs = $self->{'LDLOADLIBS'};
+ my $libpath = '';
+ while ($libs =~ s/(?:^|\s)(("?)-L.+?\2)(?:\s|$)/ /) {
+ $libpath .= ' ' if length $libpath;
+ $libpath .= $1;
+ }
+ $self->{'LDLOADLIBS'} = $libs;
+ $self->{'LDDLFLAGS'} ||= $Config{'lddlflags'};
+ $self->{'LDDLFLAGS'} .= " $libpath";
+ }
$self->{'DEV_NULL'} = '> NUL';
# $self->{'NOECHO'} = ''; # till we have it working
}
@@ -718,6 +730,7 @@ We don't want manpage process. XXX add pod2html support later.
=cut
sub manifypods {
+ my($self) = shift;
return "\nmanifypods :\n\t$self->{NOECHO}\$(NOOP)\n";
}
diff --git a/lib/File/DosGlob.pm b/lib/File/DosGlob.pm
index 24b28b2dce..594ee2ec84 100644
--- a/lib/File/DosGlob.pm
+++ b/lib/File/DosGlob.pm
@@ -97,17 +97,27 @@ my %entries;
sub glob {
my $pat = shift;
my $cxix = shift;
+ my @pat;
# glob without args defaults to $_
$pat = $_ unless defined $pat;
+ # extract patterns
+ if ($pat =~ /\s/) {
+ require Text::ParseWords;
+ @pat = Text::ParseWords::parse_line('\s+',0,$pat);
+ }
+ else {
+ push @pat, $pat;
+ }
+
# assume global context if not provided one
$cxix = '_G_' unless defined $cxix;
$iter{$cxix} = 0 unless exists $iter{$cxix};
# if we're just beginning, do it all first
if ($iter{$cxix} == 0) {
- $entries{$cxix} = [doglob(1,$pat)];
+ $entries{$cxix} = [doglob(1,@pat)];
}
# chuck it all out, quick or slow
@@ -174,6 +184,15 @@ backslashes and forward slashes are both accepted, and preserved.
You may have to double the backslashes if you are putting them in
literally, due to double-quotish parsing of the pattern by perl.
+Spaces in the argument delimit distinct patterns, so
+C<glob('*.exe *.dll')> globs all filenames that end in C<.exe>
+or C<.dll>. If you want to put in literal spaces in the glob
+pattern, you can escape them with either double quotes, or backslashes.
+e.g. C<glob('c:/"Program Files"/*/*.dll')>, or
+C<glob('c:/Program\ Files/*/*.dll')>. The argument is tokenized using
+C<Text::ParseWords::parse_line()>, so see L<Text::ParseWords> for details
+of the quoting rules used.
+
Extending it to csh patterns is left as an exercise to the reader.
=head1 EXPORTS (by request only)
@@ -224,5 +243,7 @@ perl
perlglob.bat
+Text::ParseWords
+
=cut
diff --git a/lib/Math/Complex.pm b/lib/Math/Complex.pm
index aca85c6acd..e711c1483d 100644
--- a/lib/Math/Complex.pm
+++ b/lib/Math/Complex.pm
@@ -179,7 +179,7 @@ sub cplxe {
#
# The number defined as pi = 180 degrees
#
-use constant pi => 4 * atan2(1, 1);
+use constant pi => 4 * CORE::atan2(1, 1);
#
# pit2
@@ -208,7 +208,7 @@ use constant deg1 => pi / 180;
#
# Used in log10().
#
-use constant uplog10 => 1 / log(10);
+use constant uplog10 => 1 / CORE::log(10);
#
# i
@@ -246,7 +246,7 @@ sub update_cartesian {
my $self = shift;
my ($r, $t) = @{$self->{'polar'}};
$self->{c_dirty} = 0;
- return $self->{'cartesian'} = [$r * cos $t, $r * sin $t];
+ return $self->{'cartesian'} = [$r * CORE::cos($t), $r * CORE::sin($t)];
}
#
@@ -260,7 +260,7 @@ sub update_polar {
my ($x, $y) = @{$self->{'cartesian'}};
$self->{p_dirty} = 0;
return $self->{'polar'} = [0, 0] if $x == 0 && $y == 0;
- return $self->{'polar'} = [sqrt($x*$x + $y*$y), atan2($y, $x)];
+ return $self->{'polar'} = [CORE::sqrt($x*$x + $y*$y), CORE::atan2($y, $x)];
}
#
@@ -432,7 +432,7 @@ sub power {
return 0 if ($z1z);
return 1 if ($z2z or $z1 == 1);
}
- my $w = $inverted ? exp($z1 * log $z2) : exp($z2 * log $z1);
+ my $w = $inverted ? CORE::exp($z1 * CORE::log($z2)) : CORE::exp($z2 * CORE::log($z1));
# If both arguments cartesian, return cartesian, else polar.
return $z1->{c_dirty} == 0 &&
(not ref $z2 or $z2->{c_dirty} == 0) ?
@@ -548,9 +548,9 @@ sub arg {
sub sqrt {
my ($z) = @_;
my ($re, $im) = ref $z ? @{$z->cartesian} : ($z, 0);
- return $re < 0 ? cplx(0, sqrt(-$re)) : sqrt($re) if $im == 0;
+ return $re < 0 ? cplx(0, CORE::sqrt(-$re)) : CORE::sqrt($re) if $im == 0;
my ($r, $t) = @{$z->polar};
- return (ref $z)->emake(sqrt($r), $t/2);
+ return (ref $z)->emake(CORE::sqrt($r), $t/2);
}
#
@@ -562,10 +562,10 @@ sub sqrt {
#
sub cbrt {
my ($z) = @_;
- return $z < 0 ? -exp(log(-$z)/3) : ($z > 0 ? exp(log($z)/3): 0)
+ return $z < 0 ? -CORE::exp(CORE::log(-$z)/3) : ($z > 0 ? CORE::exp(CORE::log($z)/3): 0)
unless ref $z;
my ($r, $t) = @{$z->polar};
- return (ref $z)->emake(exp(log($r)/3), $t/3);
+ return (ref $z)->emake(CORE::exp(CORE::log($r)/3), $t/3);
}
#
@@ -596,7 +596,7 @@ sub _rootbad {
sub root {
my ($z, $n) = @_;
_rootbad($n) if ($n < 1 or int($n) != $n);
- my ($r, $t) = ref $z ? @{$z->polar} : (abs($z), $z >= 0 ? 0 : pi);
+ my ($r, $t) = ref $z ? @{$z->polar} : (CORE::abs($z), $z >= 0 ? 0 : pi);
my @root;
my $k;
my $theta_inc = pit2 / $n;
@@ -671,7 +671,7 @@ sub theta {
sub exp {
my ($z) = @_;
my ($x, $y) = @{$z->cartesian};
- return (ref $z)->emake(exp($x), $y);
+ return (ref $z)->emake(CORE::exp($x), $y);
}
#
@@ -704,13 +704,13 @@ sub log {
my ($z) = @_;
unless (ref $z) {
_logofzero("log") if $z == 0;
- return $z > 0 ? log($z) : cplx(log(-$z), pi);
+ return $z > 0 ? CORE::log($z) : cplx(CORE::log(-$z), pi);
}
my ($r, $t) = @{$z->polar};
_logofzero("log") if $r == 0;
if ($t > pi()) { $t -= pit2 }
elsif ($t <= -pi()) { $t += pit2 }
- return (ref $z)->make(log($r), $t);
+ return (ref $z)->make(CORE::log($r), $t);
}
#
@@ -739,8 +739,8 @@ sub logn {
my ($z, $n) = @_;
$z = cplx($z, 0) unless ref $z;
my $logn = $logn{$n};
- $logn = $logn{$n} = log($n) unless defined $logn; # Cache log(n)
- return log($z) / $logn;
+ $logn = $logn{$n} = CORE::log($n) unless defined $logn; # Cache log(n)
+ return CORE::log($z) / $logn;
}
#
@@ -751,10 +751,10 @@ sub logn {
sub cos {
my ($z) = @_;
my ($x, $y) = @{$z->cartesian};
- my $ey = exp($y);
+ my $ey = CORE::exp($y);
my $ey_1 = 1 / $ey;
- return (ref $z)->make(cos($x) * ($ey + $ey_1)/2,
- sin($x) * ($ey_1 - $ey)/2);
+ return (ref $z)->make(CORE::cos($x) * ($ey + $ey_1)/2,
+ CORE::sin($x) * ($ey_1 - $ey)/2);
}
#
@@ -765,10 +765,10 @@ sub cos {
sub sin {
my ($z) = @_;
my ($x, $y) = @{$z->cartesian};
- my $ey = exp($y);
+ my $ey = CORE::exp($y);
my $ey_1 = 1 / $ey;
- return (ref $z)->make(sin($x) * ($ey + $ey_1)/2,
- cos($x) * ($ey - $ey_1)/2);
+ return (ref $z)->make(CORE::sin($x) * ($ey + $ey_1)/2,
+ CORE::cos($x) * ($ey - $ey_1)/2);
}
#
@@ -778,9 +778,9 @@ sub sin {
#
sub tan {
my ($z) = @_;
- my $cz = cos($z);
- _divbyzero "tan($z)", "cos($z)" if (abs($cz) < $eps);
- return sin($z) / $cz;
+ my $cz = CORE::cos($z);
+ _divbyzero "tan($z)", "cos($z)" if (CORE::abs($cz) < $eps);
+ return CORE::sin($z) / $cz;
}
#
@@ -790,7 +790,7 @@ sub tan {
#
sub sec {
my ($z) = @_;
- my $cz = cos($z);
+ my $cz = CORE::cos($z);
_divbyzero "sec($z)", "cos($z)" if ($cz == 0);
return 1 / $cz;
}
@@ -802,7 +802,7 @@ sub sec {
#
sub csc {
my ($z) = @_;
- my $sz = sin($z);
+ my $sz = CORE::sin($z);
_divbyzero "csc($z)", "sin($z)" if ($sz == 0);
return 1 / $sz;
}
@@ -821,9 +821,9 @@ sub cosec { Math::Complex::csc(@_) }
#
sub cot {
my ($z) = @_;
- my $sz = sin($z);
+ my $sz = CORE::sin($z);
_divbyzero "cot($z)", "sin($z)" if ($sz == 0);
- return cos($z) / $sz;
+ return CORE::cos($z) / $sz;
}
#
@@ -840,17 +840,17 @@ sub cotan { Math::Complex::cot(@_) }
#
sub acos {
my $z = $_[0];
- return atan2(sqrt(1-$z*$z), $z) if (! ref $z) && abs($z) <= 1;
+ return CORE::atan2(CORE::sqrt(1-$z*$z), $z) if (! ref $z) && CORE::abs($z) <= 1;
my ($x, $y) = ref $z ? @{$z->cartesian} : ($z, 0);
- my $t1 = sqrt(($x+1)*($x+1) + $y*$y);
- my $t2 = sqrt(($x-1)*($x-1) + $y*$y);
+ my $t1 = CORE::sqrt(($x+1)*($x+1) + $y*$y);
+ my $t2 = CORE::sqrt(($x-1)*($x-1) + $y*$y);
my $alpha = ($t1 + $t2)/2;
my $beta = ($t1 - $t2)/2;
$alpha = 1 if $alpha < 1;
if ($beta > 1) { $beta = 1 }
elsif ($beta < -1) { $beta = -1 }
- my $u = atan2(sqrt(1-$beta*$beta), $beta);
- my $v = log($alpha + sqrt($alpha*$alpha-1));
+ my $u = CORE::atan2(CORE::sqrt(1-$beta*$beta), $beta);
+ my $v = CORE::log($alpha + CORE::sqrt($alpha*$alpha-1));
$v = -$v if $y > 0 || ($y == 0 && $x < -1);
return $package->make($u, $v);
}
@@ -862,17 +862,17 @@ sub acos {
#
sub asin {
my $z = $_[0];
- return atan2($z, sqrt(1-$z*$z)) if (! ref $z) && abs($z) <= 1;
+ return CORE::atan2($z, CORE::sqrt(1-$z*$z)) if (! ref $z) && CORE::abs($z) <= 1;
my ($x, $y) = ref $z ? @{$z->cartesian} : ($z, 0);
- my $t1 = sqrt(($x+1)*($x+1) + $y*$y);
- my $t2 = sqrt(($x-1)*($x-1) + $y*$y);
+ my $t1 = CORE::sqrt(($x+1)*($x+1) + $y*$y);
+ my $t2 = CORE::sqrt(($x-1)*($x-1) + $y*$y);
my $alpha = ($t1 + $t2)/2;
my $beta = ($t1 - $t2)/2;
$alpha = 1 if $alpha < 1;
if ($beta > 1) { $beta = 1 }
elsif ($beta < -1) { $beta = -1 }
- my $u = atan2($beta, sqrt(1-$beta*$beta));
- my $v = -log($alpha + sqrt($alpha*$alpha-1));
+ my $u = CORE::atan2($beta, CORE::sqrt(1-$beta*$beta));
+ my $v = -CORE::log($alpha + CORE::sqrt($alpha*$alpha-1));
$v = -$v if $y > 0 || ($y == 0 && $x < -1);
return $package->make($u, $v);
}
@@ -884,10 +884,10 @@ sub asin {
#
sub atan {
my ($z) = @_;
- return atan2($z, 1) unless ref $z;
+ return CORE::atan2($z, 1) unless ref $z;
_divbyzero "atan(i)" if ( $z == i);
_divbyzero "atan(-i)" if (-$z == i);
- my $log = log((i + $z) / (i - $z));
+ my $log = CORE::log((i + $z) / (i - $z));
$ip2 = 0.5 * i unless defined $ip2;
return $ip2 * $log;
}
@@ -928,10 +928,10 @@ sub acosec { Math::Complex::acsc(@_) }
#
sub acot {
my ($z) = @_;
- _divbyzero "acot(0)" if (abs($z) < $eps);
- return ($z >= 0) ? atan2(1, $z) : atan2(-1, -$z) unless ref $z;
- _divbyzero "acot(i)" if (abs($z - i) < $eps);
- _logofzero "acot(-i)" if (abs($z + i) < $eps);
+ _divbyzero "acot(0)" if (CORE::abs($z) < $eps);
+ return ($z >= 0) ? CORE::atan2(1, $z) : CORE::atan2(-1, -$z) unless ref $z;
+ _divbyzero "acot(i)" if (CORE::abs($z - i) < $eps);
+ _logofzero "acot(-i)" if (CORE::abs($z + i) < $eps);
return atan(1 / $z);
}
@@ -951,14 +951,14 @@ sub cosh {
my ($z) = @_;
my $ex;
unless (ref $z) {
- $ex = exp($z);
+ $ex = CORE::exp($z);
return ($ex + 1/$ex)/2;
}
my ($x, $y) = @{$z->cartesian};
- $ex = exp($x);
+ $ex = CORE::exp($x);
my $ex_1 = 1 / $ex;
- return (ref $z)->make(cos($y) * ($ex + $ex_1)/2,
- sin($y) * ($ex - $ex_1)/2);
+ return (ref $z)->make(CORE::cos($y) * ($ex + $ex_1)/2,
+ CORE::sin($y) * ($ex - $ex_1)/2);
}
#
@@ -970,14 +970,14 @@ sub sinh {
my ($z) = @_;
my $ex;
unless (ref $z) {
- $ex = exp($z);
+ $ex = CORE::exp($z);
return ($ex - 1/$ex)/2;
}
my ($x, $y) = @{$z->cartesian};
- $ex = exp($x);
+ $ex = CORE::exp($x);
my $ex_1 = 1 / $ex;
- return (ref $z)->make(cos($y) * ($ex - $ex_1)/2,
- sin($y) * ($ex + $ex_1)/2);
+ return (ref $z)->make(CORE::cos($y) * ($ex - $ex_1)/2,
+ CORE::sin($y) * ($ex + $ex_1)/2);
}
#
@@ -1050,15 +1050,15 @@ sub cotanh { Math::Complex::coth(@_) }
sub acosh {
my ($z) = @_;
unless (ref $z) {
- return log($z + sqrt($z*$z-1)) if $z >= 1;
+ return CORE::log($z + CORE::sqrt($z*$z-1)) if $z >= 1;
$z = cplx($z, 0);
}
my ($re, $im) = @{$z->cartesian};
if ($im == 0) {
- return cplx(log($re + sqrt($re*$re - 1)), 0) if $re >= 1;
- return cplx(0, atan2(sqrt(1-$re*$re), $re)) if abs($re) <= 1;
+ return cplx(CORE::log($re + CORE::sqrt($re*$re - 1)), 0) if $re >= 1;
+ return cplx(0, CORE::atan2(CORE::sqrt(1-$re*$re), $re)) if CORE::abs($re) <= 1;
}
- return log($z + sqrt($z*$z - 1));
+ return CORE::log($z + CORE::sqrt($z*$z - 1));
}
#
@@ -1068,7 +1068,7 @@ sub acosh {
#
sub asinh {
my ($z) = @_;
- return log($z + sqrt($z*$z + 1));
+ return CORE::log($z + CORE::sqrt($z*$z + 1));
}
#
@@ -1079,12 +1079,12 @@ sub asinh {
sub atanh {
my ($z) = @_;
unless (ref $z) {
- return log((1 + $z)/(1 - $z))/2 if abs($z) < 1;
+ return CORE::log((1 + $z)/(1 - $z))/2 if CORE::abs($z) < 1;
$z = cplx($z, 0);
}
_divbyzero 'atanh(1)', "1 - $z" if ($z == 1);
_logofzero 'atanh(-1)' if ($z == -1);
- return 0.5 * log((1 + $z) / (1 - $z));
+ return 0.5 * CORE::log((1 + $z) / (1 - $z));
}
#
@@ -1123,14 +1123,14 @@ sub acosech { Math::Complex::acsch(@_) }
#
sub acoth {
my ($z) = @_;
- _divbyzero 'acoth(0)' if (abs($z) < $eps);
+ _divbyzero 'acoth(0)' if (CORE::abs($z) < $eps);
unless (ref $z) {
- return log(($z + 1)/($z - 1))/2 if abs($z) > 1;
+ return CORE::log(($z + 1)/($z - 1))/2 if CORE::abs($z) > 1;
$z = cplx($z, 0);
}
- _divbyzero 'acoth(1)', "$z - 1" if (abs($z - 1) < $eps);
- _logofzero 'acoth(-1)', "1 / $z" if (abs($z + 1) < $eps);
- return log((1 + $z) / ($z - 1)) / 2;
+ _divbyzero 'acoth(1)', "$z - 1" if (CORE::abs($z - 1) < $eps);
+ _logofzero 'acoth(-1)', "1 / $z" if (CORE::abs($z + 1) < $eps);
+ return CORE::log((1 + $z) / ($z - 1)) / 2;
}
#
@@ -1156,7 +1156,7 @@ sub atan2 {
($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
}
if ($im2 == 0) {
- return cplx(atan2($re1, $re2), 0) if $im1 == 0;
+ return cplx(CORE::atan2($re1, $re2), 0) if $im1 == 0;
return cplx(($im1<=>0) * pip2, 0) if $re2 == 0;
}
my $w = atan($z1/$z2);
@@ -1232,14 +1232,14 @@ sub stringify_cartesian {
my ($re, $im);
$x = int($x + ($x < 0 ? -1 : 1) * $eps)
- if int(abs($x)) != int(abs($x) + $eps);
+ if int(CORE::abs($x)) != int(CORE::abs($x) + $eps);
$y = int($y + ($y < 0 ? -1 : 1) * $eps)
- if int(abs($y)) != int(abs($y) + $eps);
+ if int(CORE::abs($y)) != int(CORE::abs($y) + $eps);
- $re = "$x" if abs($x) >= $eps;
+ $re = "$x" if CORE::abs($x) >= $eps;
if ($y == 1) { $im = 'i' }
elsif ($y == -1) { $im = '-i' }
- elsif (abs($y) >= $eps) { $im = $y . "i" }
+ elsif (CORE::abs($y) >= $eps) { $im = $y . "i" }
my $str = '';
$str = $re if defined $re;
@@ -1298,15 +1298,15 @@ sub stringify_polar {
$nt = ($nt - int($nt)) * pit2;
$nt += pit2 if $nt < 0; # Range [0, 2pi]
- if (abs($nt) <= $eps) { $theta = 0 }
- elsif (abs(pi-$nt) <= $eps) { $theta = 'pi' }
+ if (CORE::abs($nt) <= $eps) { $theta = 0 }
+ elsif (CORE::abs(pi-$nt) <= $eps) { $theta = 'pi' }
if (defined $theta) {
$r = int($r + ($r < 0 ? -1 : 1) * $eps)
- if int(abs($r)) != int(abs($r) + $eps);
+ if int(CORE::abs($r)) != int(CORE::abs($r) + $eps);
$theta = int($theta + ($theta < 0 ? -1 : 1) * $eps)
if ($theta ne 'pi' and
- int(abs($theta)) != int(abs($theta) + $eps));
+ int(CORE::abs($theta)) != int(CORE::abs($theta) + $eps));
return "\[$r,$theta\]";
}
@@ -1316,13 +1316,13 @@ sub stringify_polar {
$nt -= pit2 if $nt > pi;
- if (abs($nt) >= deg1) {
+ if (CORE::abs($nt) >= deg1) {
my ($n, $k, $kpi);
for ($k = 1, $kpi = pi; $k < 10; $k++, $kpi += pi) {
$n = int($kpi / $nt + ($nt > 0 ? 1 : -1) * 0.5);
- if (abs($kpi/$n - $nt) <= $eps) {
- $n = abs $n;
+ if (CORE::abs($kpi/$n - $nt) <= $eps) {
+ $n = CORE::abs($n);
my $gcd = gcd($k, $n);
if ($gcd > 1) {
$k /= $gcd;
@@ -1340,10 +1340,10 @@ sub stringify_polar {
$theta = $nt unless defined $theta;
$r = int($r + ($r < 0 ? -1 : 1) * $eps)
- if int(abs($r)) != int(abs($r) + $eps);
+ if int(CORE::abs($r)) != int(CORE::abs($r) + $eps);
$theta = int($theta + ($theta < 0 ? -1 : 1) * $eps)
if ($theta !~ m(^-?\d*pi/\d+$) and
- int(abs($theta)) != int(abs($theta) + $eps));
+ int(CORE::abs($theta)) != int(CORE::abs($theta) + $eps));
return "\[$r,$theta\]";
}
diff --git a/lib/Pod/Html.pm b/lib/Pod/Html.pm
index a0dc4b3f11..5d2e07b2af 100644
--- a/lib/Pod/Html.pm
+++ b/lib/Pod/Html.pm
@@ -1293,7 +1293,7 @@ sub process_puretext {
} elsif ($word =~ m,^\w+://\w,) {
# looks like a URL
$word = qq(<A HREF="$word">$word</A>);
- } elsif ($word =~ /[\w.-]+\@\w+\.\w/) {
+ } elsif ($word =~ /[\w.-]+\@[\w-]+\.\w/) {
# looks like an e-mail address
my ($w1, $w2, $w3) = ("", $word, "");
($w1, $w2, $w3) = ("(", $1, ")$2") if $word =~ /^\((.*?)\)(,?)/;
diff --git a/lib/Test.pm b/lib/Test.pm
index 5f198c234c..6f57415efd 100644
--- a/lib/Test.pm
+++ b/lib/Test.pm
@@ -225,7 +225,7 @@ L<Test::Harness> and various test coverage analysis tools.
=head1 AUTHOR
-Copyright © 1998 Joshua Nathaniel Pritikin. All rights reserved.
+Copyright (C) 1998 Joshua Nathaniel Pritikin. All rights reserved.
This package is free software and is provided "as is" without express
or implied warranty. It may be used, redistributed and/or modified
diff --git a/lib/Test/Harness.pm b/lib/Test/Harness.pm
index 5decc756ff..9c61d3a9dd 100644
--- a/lib/Test/Harness.pm
+++ b/lib/Test/Harness.pm
@@ -16,6 +16,8 @@ $VERSION = "1.1602";
# Some experimental versions of OS/2 build have broken $?
my $ignore_exitcode = $ENV{HARNESS_IGNORE_EXITCODE};
+my $files_in_dir = $ENV{HARNESS_FILELEAK_IN_DIR};
+
my $tests_skipped = 0;
my $subtests_skipped = 0;
@@ -46,6 +48,8 @@ format STDOUT =
$verbose = 0;
$switches = "-w";
+sub globdir { opendir DIRH, shift; my @f = readdir DIRH; closedir DIRH; @f }
+
sub runtests {
my(@tests) = @_;
local($|) = 1;
@@ -62,6 +66,7 @@ sub runtests {
if ($^O eq 'VMS') { $switches =~ s/-(\S*[A-Z]\S*)/"-$1"/g }
+ my @dir_files = globdir $files_in_dir if defined $files_in_dir;
my $t_start = new Benchmark;
while ($test = shift(@tests)) {
$te = $test;
@@ -212,6 +217,17 @@ sub runtests {
};
}
$subtests_skipped += $skipped;
+ if (defined $files_in_dir) {
+ my @new_dir_files = globdir $files_in_dir;
+ if (@new_dir_files != @dir_files) {
+ my %f;
+ @f{@new_dir_files} = (1) x @new_dir_files;
+ delete @f{@dir_files};
+ my @f = sort keys %f;
+ print "LEAKED FILES: @f\n";
+ @dir_files = @new_dir_files;
+ }
+ }
}
my $t_total = timediff(new Benchmark, $t_start);
@@ -421,9 +437,19 @@ above messages.
=head1 ENVIRONMENT
-Setting C<HARNESS_IGNORE_EXITCODE> makes it ignore the exit status
+Setting C<HARNESS_IGNORE_EXITCODE> makes harness ignore the exit status
of child processes.
+If C<HARNESS_FILELEAK_IN_DIR> is set to the name of a directory, harness
+will check after each test whether new files appeared in that directory,
+and report them as
+
+ LEAKED FILES: scr.tmp 0 my.db
+
+If relative, directory name is with respect to the current directory at
+the moment runtests() was called. Putting absolute path into
+C<HARNESS_FILELEAK_IN_DIR> may give more predicatable results.
+
=head1 SEE ALSO
L<Test> for writing test scripts and also L<Benchmark> for the
diff --git a/lib/bigint.pl b/lib/bigint.pl
index bfd2efa88c..adeb17f28a 100644
--- a/lib/bigint.pl
+++ b/lib/bigint.pl
@@ -74,7 +74,7 @@ sub external { #(int_num_array) return num_str
sub main'bneg { #(num_str) return num_str
local($_) = &'bnorm(@_);
vec($_,0,8) ^= ord('+') ^ ord('-') unless $_ eq '+0';
- s/^H/N/;
+ s/^./N/ unless /^[-+]/; # works both in ASCII and EBCDIC
$_;
}
diff --git a/lib/dumpvar.pl b/lib/dumpvar.pl
index cc7da89a62..32d4692d13 100644
--- a/lib/dumpvar.pl
+++ b/lib/dumpvar.pl
@@ -23,6 +23,7 @@ $tick = "auto" unless defined $tick;
$unctrl = 'quote' unless defined $unctrl;
$subdump = 1;
$dumpReused = 0 unless defined $dumpReused;
+$bareStringify = 1 unless defined $bareStringify;
sub main::dumpValue {
local %address;
@@ -50,6 +51,10 @@ sub stringify {
return 'undef' unless defined $_ or not $printUndef;
return $_ . "" if ref \$_ eq 'GLOB';
+ $_ = &{'overload::StrVal'}($_)
+ if $bareStringify and ref $_
+ and defined %overload:: and defined &{'overload::StrVal'};
+
if ($tick eq 'auto') {
if (/[\000-\011\013-\037\177]/) {
$tick = '"';
@@ -110,7 +115,7 @@ sub unwrap {
return if $DB::signal;
local($v) = shift ;
local($s) = shift ; # extra no of spaces
- local(%v,@v,$sp,$value,$key,$type,@sortKeys,$more,$shortmore,$short) ;
+ local(%v,@v,$sp,$value,$key,@sortKeys,$more,$shortmore,$short) ;
local($tHashDepth,$tArrayDepth) ;
$sp = " " x $s ;
@@ -118,9 +123,11 @@ sub unwrap {
# Check for reused addresses
if (ref $v) {
- ($address) = $v =~ /(0x[0-9a-f]+)\)$/ ;
+ my $val = $v;
+ $val = &{'overload::StrVal'}($v)
+ if defined %overload:: and defined &{'overload::StrVal'};
+ ($address) = $val =~ /(0x[0-9a-f]+)\)$/ ;
if (!$dumpReused && defined $address) {
- ($type) = $v =~ /=(.*?)\([^=]+$/ ;
$address{$address}++ ;
if ( $address{$address} > 1 ) {
print "${sp}-> REUSED_ADDRESS\n" ;
diff --git a/lib/overload.pm b/lib/overload.pm
index dfcdb02b1e..43fef8ae5e 100644
--- a/lib/overload.pm
+++ b/lib/overload.pm
@@ -62,7 +62,10 @@ sub OverloadedStringify {
my $package = shift;
$package = ref $package if ref $package;
#$package->can('(""')
- ov_method mycan($package, '(""'), $package;
+ 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 {
@@ -108,6 +111,18 @@ sub mycan { # Real can would leave stubs.
'qr' => 0x10000,
);
+%ops = ( with_assign => "+ - * / % ** << >> x .",
+ assign => "+= -= *= /= %= **= <<= >>= x= .=",
+ str_comparison => "< <= > >= == !=",
+ '3way_comparison'=> "<=> cmp",
+ num_comparison => "lt le gt ge eq ne",
+ binary => "& | ^",
+ unary => "neg ! ~",
+ mutators => '++ --',
+ func => "atan2 cos sin exp abs log sqrt",
+ conversion => 'bool "" 0+',
+ special => 'nomethod fallback =');
+
sub constant {
# Arguments: what, sub
while (@_) {
@@ -220,7 +235,8 @@ the arguments are reversed.
the current operation is an assignment variant (as in
C<$a+=7>), but the usual function is called instead. This additional
-information can be used to generate some optimizations.
+information can be used to generate some optimizations. Compare
+L<Calling Conventions for Mutators>.
=back
@@ -230,9 +246,67 @@ Unary operation are considered binary operations with the second
argument being C<undef>. Thus the functions that overloads C<{"++"}>
is called with arguments C<($a,undef,'')> when $a++ is executed.
+=head2 Calling Conventions for Mutators
+
+Two types of mutators have different calling conventions:
+
+=over
+
+=item C<++> and C<-->
+
+The routines which implement these operators are expected to actually
+I<mutate> their arguments. So, assuming that $obj is a reference to a
+number,
+
+ sub incr { my $n = $ {$_[0]}; ++$n; $_[0] = bless \$n}
+
+is an appropriate implementation of overloaded C<++>. Note that
+
+ sub incr { ++$ {$_[0]} ; shift }
+
+is OK if used with preincrement and with postincrement. (In the case
+of postincrement a copying will be performed, see L<Copy Constructor>.)
+
+=item C<x=> and other assignment versions
+
+There is nothing special about these methods. They may change the
+value of their arguments, and may leave it as is. The result is going
+to be assigned to the value in the left-hand-side if different from
+this value.
+
+This allows for the same method to be used as averloaded C<+=> and
+C<+>. Note that this is I<allowed>, but not recommended, since by the
+semantic of L<"Fallback"> Perl will call the method for C<+> anyway,
+if C<+=> is not overloaded.
+
+=back
+
+B<Warning.> Due to the presense of assignment versions of operations,
+routines which may be called in assignment context may create
+self-referencial structures. Currently Perl will not free self-referential
+structures until cycles are C<explicitly> broken. You may get problems
+when traversing your structures too.
+
+Say,
+
+ use overload '+' => sub { bless [ \$_[0], \$_[1] ] };
+
+is asking for trouble, since for code C<$obj += $foo> the subroutine
+is called as C<$obj = add($obj, $foo, undef)>, or C<$obj = [\$obj,
+\$foo]>. If using such a subroutine is an important optimization, one
+can overload C<+=> explicitly by a non-"optimized" version, or switch
+to non-optimized version if C<not defined $_[2]> (see
+L<Calling Conventions for Binary Operations>).
+
+Even if no I<explicit> assignment-variants of operators are present in
+the script, they may be generated by the optimizer. Say, C<",$obj,"> or
+C<',' . $obj . ','> may be both optimized to
+
+ my $tmp = ',' . $obj; $tmp .= ',';
+
=head2 Overloadable Operations
-The following symbols can be specified in C<use overload>:
+The following symbols can be specified in C<use overload> directive:
=over 5
@@ -247,6 +321,10 @@ the assignment variant is not available. Methods for operations "C<+>",
increment and decrement methods. The operation "C<->" can be used to
autogenerate missing methods for unary minus or C<abs>.
+See L<"MAGIC AUTOGENERATION">, L<"Calling Conventions for Mutators"> and
+L<"Calling Conventions for Binary Operations">) for details of these
+substitutions.
+
=item * I<Comparison operations>
"<", "<=", ">", ">=", "==", "!=", "<=>",
@@ -298,7 +376,23 @@ see L<SPECIAL SYMBOLS FOR C<use overload>>.
=back
-See L<"Fallback"> for an explanation of when a missing method can be autogenerated.
+See L<"Fallback"> for an explanation of when a missing method can be
+autogenerated.
+
+A computer-readable form of the above table is available in the hash
+%overload::ops, with values being space-separated lists of names:
+
+ with_assign => '+ - * / % ** << >> x .',
+ assign => '+= -= *= /= %= **= <<= >>= x= .=',
+ str_comparison => '< <= > >= == !=',
+ '3way_comparison'=> '<=> cmp',
+ num_comparison => 'lt le gt ge eq ne',
+ binary => '& | ^',
+ unary => 'neg ! ~',
+ mutators => '++ --',
+ func => 'atan2 cos sin exp abs log sqrt',
+ conversion => 'bool "" 0+',
+ special => 'nomethod fallback ='
=head2 Inheritance and overloading
@@ -401,15 +495,15 @@ to a reference that shares its object with some other reference, such
as
$a=$b;
- $a++;
+ ++$a;
To make this change $a and not change $b, a copy of C<$$a> is made,
and $a is assigned a reference to this new object. This operation is
-done during execution of the C<$a++>, and not during the assignment,
+done during execution of the C<++$a>, and not during the assignment,
(so before the increment C<$$a> coincides with C<$$b>). This is only
-done if C<++> is expressed via a method for C<'++'> or C<'+='>. Note
-that if this operation is expressed via C<'+'> a nonmutator, i.e., as
-in
+done if C<++> is expressed via a method for C<'++'> or C<'+='> (or
+C<nomethod>). Note that if this operation is expressed via C<'+'>
+a nonmutator, i.e., as in
$a=$b;
$a=$a+1;
@@ -443,6 +537,9 @@ C<'='> was overloaded with C<\&clone>.
=back
+Same behaviour is triggered by C<$b = $a++>, which is consider a synonim for
+C<$b = $a; ++$a>.
+
=head1 MAGIC AUTOGENERATION
If a method for an operation is not found, and the value for C<"fallback"> is
@@ -499,7 +596,7 @@ value is a scalar and not a reference.
=back
-=head1 WARNING
+=head1 Losing overloading
The restriction for the comparison operation is that even if, for example,
`C<cmp>' should return a blessed reference, the autogenerated `C<lt>'
@@ -661,6 +758,416 @@ behavior by defining your own copy constructor (see L<"Copy Constructor">).
It is expected that arguments to methods that are not explicitly supposed
to be changed are constant (but this is not enforced).
+=head1 Metaphor clash
+
+One may wonder why the semantic of overloaded C<=> is so counterintuive.
+If it I<looks> counterintuive to you, you are subject to a metaphor
+clash.
+
+Here is a Perl object metaphor:
+
+I< object is a reference to blessed data>
+
+and an arithmetic metaphor:
+
+I< object is a thing by itself>.
+
+The I<main> problem of overloading C<=> is the fact that these metaphors
+imply different actions on the assignment C<$a = $b> if $a and $b are
+objects. Perl-think implies that $a becomes a reference to whatever
+$b was referencing. Arithmetic-think implies that the value of "object"
+$a is changed to become the value of the object $b, preserving the fact
+that $a and $b are separate entities.
+
+The difference is not relevant in the absence of mutators. After
+a Perl-way assignment an operation which mutates the data referenced by $a
+would change the data referenced by $b too. Effectively, after
+C<$a = $b> values of $a and $b become I<indistinguishable>.
+
+On the other hand, anyone who has used algebraic notation knows the
+expressive power of the arithmetic metaphor. Overloading works hard
+to enable this metaphor while preserving the Perlian way as far as
+possible. Since it is not not possible to freely mix two contradicting
+metaphors, overloading allows the arithmetic way to write things I<as
+far as all the mutators are called via overloaded access only>. The
+way it is done is described in L<Copy Constructor>.
+
+If some mutator methods are directly applied to the overloaded values,
+one may need to I<explicitly unlink> other values which references the
+same value:
+
+ $a = new Data 23;
+ ...
+ $b = $a; # $b is "linked" to $a
+ ...
+ $a = $a->clone; # Unlink $b from $a
+ $a->increment_by(4);
+
+Note that overloaded access makes this transparent:
+
+ $a = new Data 23;
+ $b = $a; # $b is "linked" to $a
+ $a += 4; # would unlink $b automagically
+
+However, it would not make
+
+ $a = new Data 23;
+ $a = 4; # Now $a is a plain 4, not 'Data'
+
+preserve "objectness" of $a. But Perl I<has> a way to make assignments
+to an object do whatever you want. It is just not the overload, but
+tie()ing interface (see L<perlfunc/tie>). Adding a FETCH() method
+which returns the object itself, and STORE() method which changes the
+value of the object, one can reproduce the arithmetic metaphor in its
+completeness, at least for variables which were tie()d from the start.
+
+(Note that a workaround for a bug may be needed, see L<"BUGS">.)
+
+=head1 Cookbook
+
+Please add examples to what follows!
+
+=head2 Two-face scalars
+
+Put this in F<two_face.pm> in your Perl library directory:
+
+ package two_face; # Scalars with separate string and
+ # numeric values.
+ sub new { my $p = shift; bless [@_], $p }
+ use overload '""' => \&str, '0+' => \&num, fallback => 1;
+ sub num {shift->[1]}
+ sub str {shift->[0]}
+
+Use it as follows:
+
+ require two_face;
+ my $seven = new two_face ("vii", 7);
+ printf "seven=$seven, seven=%d, eight=%d\n", $seven, $seven+1;
+ print "seven contains `i'\n" if $seven =~ /i/;
+
+(The second line creates a scalar which has both a string value, and a
+numeric value.) This prints:
+
+ seven=vii, seven=7, eight=8
+ seven contains `i'
+
+=head2 Symbolic calculator
+
+Put this in F<symbolic.pm> in your Perl library directory:
+
+ package symbolic; # Primitive symbolic calculator
+ use overload nomethod => \&wrap;
+
+ sub new { shift; bless ['n', @_] }
+ sub wrap {
+ my ($obj, $other, $inv, $meth) = @_;
+ ($obj, $other) = ($other, $obj) if $inv;
+ bless [$meth, $obj, $other];
+ }
+
+This module is very unusual as overloaded modules go: it does not
+provide any usual overloaded operators, instead it provides the L<Last
+Resort> operator C<nomethod>. In this example the corresponding
+subroutine returns an object which encupsulates operations done over
+the objects: C<new symbolic 3> contains C<['n', 3]>, C<2 + new
+symbolic 3> contains C<['+', 2, ['n', 3]]>.
+
+Here is an example of the script which "calculates" the side of
+circumscribed octagon using the above package:
+
+ require symbolic;
+ my $iter = 1; # 2**($iter+2) = 8
+ my $side = new symbolic 1;
+ my $cnt = $iter;
+
+ while ($cnt--) {
+ $side = (sqrt(1 + $side**2) - 1)/$side;
+ }
+ print "OK\n";
+
+The value of $side is
+
+ ['/', ['-', ['sqrt', ['+', 1, ['**', ['n', 1], 2]],
+ undef], 1], ['n', 1]]
+
+Note that while we obtained this value using a nice little script,
+there is no simple way to I<use> this value. In fact this value may
+be inspected in debugger (see L<perldebug>), but ony if
+C<bareStringify> B<O>ption is set, and not via C<p> command.
+
+If one attempts to print this value, then the overloaded operator
+C<""> will be called, which will call C<nomethod> operator. The
+result of this operator will be stringified again, but this result is
+again of type C<symbolic>, which will lead to an infinite loop.
+
+Add a pretty-printer method to the module F<symbolic.pm>:
+
+ sub pretty {
+ my ($meth, $a, $b) = @{+shift};
+ $a = 'u' unless defined $a;
+ $b = 'u' unless defined $b;
+ $a = $a->pretty if ref $a;
+ $b = $b->pretty if ref $b;
+ "[$meth $a $b]";
+ }
+
+Now one can finish the script by
+
+ print "side = ", $side->pretty, "\n";
+
+The method C<pretty> is doing object-to-string conversion, so it
+is natural to overload the operator C<""> using this method. However,
+inside such a method it is not necessary to pretty-print the
+I<components> $a and $b of an object. In the above subroutine
+C<"[$meth $a $b]"> is a catenation of some strings and components $a
+and $b. If these components use overloading, the catenation operator
+will look for an overloaded operator C<.>, if not present, it will
+look for an overloaded operator C<"">. Thus it is enough to use
+
+ use overload nomethod => \&wrap, '""' => \&str;
+ sub str {
+ my ($meth, $a, $b) = @{+shift};
+ $a = 'u' unless defined $a;
+ $b = 'u' unless defined $b;
+ "[$meth $a $b]";
+ }
+
+Now one can change the last line of the script to
+
+ print "side = $side\n";
+
+which outputs
+
+ side = [/ [- [sqrt [+ 1 [** [n 1 u] 2]] u] 1] [n 1 u]]
+
+and one can inspect the value in debugger using all the possible
+methods.
+
+Something is is still amiss: consider the loop variable $cnt of the
+script. It was a number, not an object. We cannot make this value of
+type C<symbolic>, since then the loop will not terminate.
+
+Indeed, to terminate the cycle, the $cnt should become false.
+However, the operator C<bool> for checking falsity is overloaded (this
+time via overloaded C<"">), and returns a long string, thus any object
+of type C<symbolic> is true. To overcome this, we need a way to
+compare an object to 0. In fact, it is easier to write a numeric
+conversion routine.
+
+Here is the text of F<symbolic.pm> with such a routine added (and
+slightly modifed str()):
+
+ package symbolic; # Primitive symbolic calculator
+ use overload
+ nomethod => \&wrap, '""' => \&str, '0+' => \&num;
+
+ sub new { shift; bless ['n', @_] }
+ sub wrap {
+ my ($obj, $other, $inv, $meth) = @_;
+ ($obj, $other) = ($other, $obj) if $inv;
+ bless [$meth, $obj, $other];
+ }
+ sub str {
+ my ($meth, $a, $b) = @{+shift};
+ $a = 'u' unless defined $a;
+ if (defined $b) {
+ "[$meth $a $b]";
+ } else {
+ "[$meth $a]";
+ }
+ }
+ my %subr = ( n => sub {$_[0]},
+ sqrt => sub {sqrt $_[0]},
+ '-' => sub {shift() - shift()},
+ '+' => sub {shift() + shift()},
+ '/' => sub {shift() / shift()},
+ '*' => sub {shift() * shift()},
+ '**' => sub {shift() ** shift()},
+ );
+ sub num {
+ my ($meth, $a, $b) = @{+shift};
+ my $subr = $subr{$meth}
+ or die "Do not know how to ($meth) in symbolic";
+ $a = $a->num if ref $a eq __PACKAGE__;
+ $b = $b->num if ref $b eq __PACKAGE__;
+ $subr->($a,$b);
+ }
+
+All the work of numeric conversion is done in %subr and num(). Of
+course, %subr is not complete, it contains only operators used in teh
+example below. Here is the extra-credit question: why do we need an
+explicit recursion in num()? (Answer is at the end of this section.)
+
+Use this module like this:
+
+ require symbolic;
+ my $iter = new symbolic 2; # 16-gon
+ my $side = new symbolic 1;
+ my $cnt = $iter;
+
+ while ($cnt) {
+ $cnt = $cnt - 1; # Mutator `--' not implemented
+ $side = (sqrt(1 + $side**2) - 1)/$side;
+ }
+ printf "%s=%f\n", $side, $side;
+ printf "pi=%f\n", $side*(2**($iter+2));
+
+It prints (without so many line breaks)
+
+ [/ [- [sqrt [+ 1 [** [/ [- [sqrt [+ 1 [** [n 1] 2]]] 1]
+ [n 1]] 2]]] 1]
+ [/ [- [sqrt [+ 1 [** [n 1] 2]]] 1] [n 1]]]=0.198912
+ pi=3.182598
+
+The above module is very primitive. It does not implement
+mutator methods (C<++>, C<-=> and so on), does not do deep copying
+(not required without mutators!), and implements only those arithmetic
+operations which are used in the example.
+
+To implement most arithmetic operattions is easy, one should just use
+the tables of operations, and change the code which fills %subr to
+
+ my %subr = ( 'n' => sub {$_[0]} );
+ foreach my $op (split " ", $overload::ops{with_assign}) {
+ $subr{$op} = $subr{"$op="} = eval "sub {shift() $op shift()}";
+ }
+ my @bins = qw(binary 3way_comparison num_comparison str_comparison);
+ foreach my $op (split " ", "@overload::ops{ @bins }") {
+ $subr{$op} = eval "sub {shift() $op shift()}";
+ }
+ foreach my $op (split " ", "@overload::ops{qw(unary func)}") {
+ print "defining `$op'\n";
+ $subr{$op} = eval "sub {$op shift()}";
+ }
+
+Due to L<Calling Conventions for Mutators>, we do not need anything
+special to make C<+=> and friends work, except filling C<+=> entry of
+%subr, and defining a copy constructor (needed since Perl has no
+way to know that the implementation of C<'+='> does not mutate
+the argument, compare L<Copy Constructor>).
+
+To implement a copy constructor, add C<'=' => \&cpy> to C<use overload>
+line, and code (this code assumes that mutators change things one level
+deep only, so recursive copying is not needed):
+
+ sub cpy {
+ my $self = shift;
+ bless [@$self], ref $self;
+ }
+
+To make C<++> and C<--> work, we need to implement actual mutators,
+either directly, or in C<nomethod>. We continue to do things inside
+C<nomethod>, thus add
+
+ if ($meth eq '++' or $meth eq '--') {
+ @$obj = ($meth, (bless [@$obj]), 1); # Avoid circular reference
+ return $obj;
+ }
+
+after the first line of wrap(). This is not a most effective
+implementation, one may consider
+
+ sub inc { $_[0] = bless ['++', shift, 1]; }
+
+instead.
+
+As a final remark, note that one can fill %subr by
+
+ my %subr = ( 'n' => sub {$_[0]} );
+ foreach my $op (split " ", $overload::ops{with_assign}) {
+ $subr{$op} = $subr{"$op="} = eval "sub {shift() $op shift()}";
+ }
+ my @bins = qw(binary 3way_comparison num_comparison str_comparison);
+ foreach my $op (split " ", "@overload::ops{ @bins }") {
+ $subr{$op} = eval "sub {shift() $op shift()}";
+ }
+ foreach my $op (split " ", "@overload::ops{qw(unary func)}") {
+ $subr{$op} = eval "sub {$op shift()}";
+ }
+ $subr{'++'} = $subr{'+'};
+ $subr{'--'} = $subr{'-'};
+
+This finishes implementation of a primitive symbolic calculator in
+50 lines of Perl code. Since the numeric values of subexpressions
+are not cached, the calculator is very slow.
+
+Here is the answer for the exercise: In the case of str(), we need no
+explicit recursion since the overloaded C<.>-operator will fall back
+to an existing overloaded operator C<"">. Overloaded arithmetic
+operators I<do not> fall back to numeric conversion if C<fallback> is
+not explicitly requested. Thus without an explicit recursion num()
+would convert C<['+', $a, $b]> to C<$a + $b>, which would just rebuild
+the argument of num().
+
+If you wonder why defaults for conversion are different for str() and
+num(), note how easy it was to write the symbolic calculator. This
+simplicity is due to an appropriate choice of defaults. One extra
+note: due to teh explicit recursion num() is more fragile than sym():
+we need to explicitly check for the type of $a and $b. If componets
+$a and $b happen to be of some related type, this may lead to problems.
+
+=head2 I<Really> symbolic calculator
+
+One may wonder why we call the above calculator symbolic. The reason
+is that the actual calculation of the value of expression is postponed
+until the value is I<used>.
+
+To see it in action, add a method
+
+ sub STORE {
+ my $obj = shift;
+ $#$obj = 1;
+ @$obj->[0,1] = ('=', shift);
+ }
+
+to the package C<symbolic>. After this change one can do
+
+ my $a = new symbolic 3;
+ my $b = new symbolic 4;
+ my $c = sqrt($a**2 + $b**2);
+
+and the numeric value of $c becomes 5. However, after calling
+
+ $a->STORE(12); $b->STORE(5);
+
+the numeric value of $c becomes 13. There is no doubt now that the module
+symbolic provides a I<symbolic> calculator indeed.
+
+To hide the rough edges under the hood, provide a tie()d interface to the
+package C<symbolic> (compare with L<Metaphor clash>). Add methods
+
+ sub TIESCALAR { my $pack = shift; $pack->new(@_) }
+ sub FETCH { shift }
+ sub nop { } # Around a bug
+
+(the bug is described in L<"BUGS">). One can use this new interface as
+
+ tie $a, 'symbolic', 3;
+ tie $b, 'symbolic', 4;
+ $a->nop; $b->nop; # Around a bug
+
+ my $c = sqrt($a**2 + $b**2);
+
+Now numeric value of $c is 5. After C<$a = 12; $b = 5> the numeric value
+of $c becomes 13. To insulate the user of the module add a method
+
+ sub vars { my $p = shift; tie($_, $p), $_->nop foreach @_; }
+
+Now
+
+ my ($a, $b);
+ symbolic->vars($a, $b);
+ my $c = sqrt($a**2 + $b**2);
+
+ $a = 3; $b = 4;
+ printf "c5 %s=%f\n", $c, $c;
+
+ $a = 12; $b = 5;
+ printf "c13 %s=%f\n", $c, $c;
+
+shows that the numeric value of $c follows changes to the values of $a
+and $b.
+
=head1 AUTHOR
Ilya Zakharevich E<lt>F<ilya@math.mps.ohio-state.edu>E<gt>.
@@ -676,7 +1183,7 @@ this overloading). Say, if C<eq> is overloaded, then the method C<(eq>
is shown by debugger. The method C<()> corresponds to the C<fallback>
key (in fact a presence of this method shows that this package has
overloading enabled, and it is what is used by the C<Overloaded>
-function).
+function of module C<overload>).
=head1 BUGS
@@ -689,9 +1196,21 @@ C<fallback> is present (possibly undefined). This may create
interesting effects if some package is not overloaded, but inherits
from two overloaded packages.
+Relation between overloading and tie()ing is broken. Overloading is
+triggered or not basing on the I<previous> class of tie()d value.
+
+This happens because the presence of overloading is checked too early,
+before any tie()d access is attempted. If the FETCH()ed class of the
+tie()d value does not change, a simple workaround is to access the value
+immediately after tie()ing, so that after this call the I<previous> class
+coincides with the current one.
+
+B<Needed:> a way to fix this without a speed penalty.
+
Barewords are not covered by overloaded string constants.
-This document is confusing.
+This document is confusing. There are grammos and misleading language
+used in places. It would seem a total rewrite is needed.
=cut
diff --git a/lib/perl5db.pl b/lib/perl5db.pl
index 67a6a6d839..099a49b49f 100644
--- a/lib/perl5db.pl
+++ b/lib/perl5db.pl
@@ -2,7 +2,7 @@ package DB;
# Debugger for Perl 5.00x; perl5db.pl patch level:
-$VERSION = 1.03;
+$VERSION = 1.0401;
$header = "perl5db.pl version $VERSION";
# Enhanced by ilya@math.ohio-state.edu (Ilya Zakharevich)
@@ -179,7 +179,7 @@ $inhibit_exit = $option{PrintRet} = 1;
TTY noTTY ReadLine NonStop LineInfo maxTraceLen
recallCommand ShellBang pager tkRunning ornaments
signalLevel warnLevel dieLevel inhibit_exit
- ImmediateStop);
+ ImmediateStop bareStringify);
%optionVars = (
hashDepth => \$dumpvar::hashDepth,
@@ -191,6 +191,7 @@ $inhibit_exit = $option{PrintRet} = 1;
undefPrint => \$dumpvar::printUndef,
globPrint => \$dumpvar::globPrint,
UsageOnly => \$dumpvar::usageOnly,
+ bareStringify => \$dumpvar::bareStringify,
frame => \$frame,
AutoTrace => \$trace,
inhibit_exit => \$inhibit_exit,
@@ -390,6 +391,7 @@ sub DB {
if ($trace & 2) {
for (my $n = 0; $n <= $#to_watch; $n++) {
$evalarg = $to_watch[$n];
+ local $onetimeDump; # Do not output results
my ($val) = &eval; # Fix context (&eval is doing array)?
$val = ( (defined $val) ? "'$val'" : 'undef' );
if ($val ne $old_watch[$n]) {
@@ -1823,6 +1825,7 @@ B<O> [I<opt>[B<=>I<val>]] [I<opt>B<\">I<val>B<\">] [I<opt>B<?>]...
I<DumpPackages>: dump symbol tables of packages;
I<DumpReused>: dump contents of \"reused\" addresses;
I<quote>, I<HighBit>, I<undefPrint>: change style of string dump;
+ I<bareStringify>: Do not print the overload-stringified value;
Option I<PrintRet> affects printing of return value after B<r> command,
I<frame> affects printing messages on entry and exit from subroutines.
I<AutoTrace> affects printing messages on every possible breaking point.