xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/overload.t (revision 0:68f95e015346)
1#!./perl
2
3BEGIN {
4    chdir 't' if -d 't';
5    @INC = '../lib';
6}
7
8package Oscalar;
9use overload (
10				# Anonymous subroutines:
11'+'	=>	sub {new Oscalar $ {$_[0]}+$_[1]},
12'-'	=>	sub {new Oscalar
13		       $_[2]? $_[1]-${$_[0]} : ${$_[0]}-$_[1]},
14'<=>'	=>	sub {new Oscalar
15		       $_[2]? $_[1]-${$_[0]} : ${$_[0]}-$_[1]},
16'cmp'	=>	sub {new Oscalar
17		       $_[2]? ($_[1] cmp ${$_[0]}) : (${$_[0]} cmp $_[1])},
18'*'	=>	sub {new Oscalar ${$_[0]}*$_[1]},
19'/'	=>	sub {new Oscalar
20		       $_[2]? $_[1]/${$_[0]} :
21			 ${$_[0]}/$_[1]},
22'%'	=>	sub {new Oscalar
23		       $_[2]? $_[1]%${$_[0]} : ${$_[0]}%$_[1]},
24'**'	=>	sub {new Oscalar
25		       $_[2]? $_[1]**${$_[0]} : ${$_[0]}-$_[1]},
26
27qw(
28""	stringify
290+	numify)			# Order of arguments unsignificant
30);
31
32sub new {
33  my $foo = $_[1];
34  bless \$foo, $_[0];
35}
36
37sub stringify { "${$_[0]}" }
38sub numify { 0 + "${$_[0]}" }	# Not needed, additional overhead
39				# comparing to direct compilation based on
40				# stringify
41
42package main;
43
44our $test = 0;
45$| = 1;
46print "1..",&last,"\n";
47
48sub test {
49  $test++;
50  if (@_ > 1) {
51    my $comment = "";
52    $comment = " # " . $_ [2] if @_ > 2;
53    if ($_[0] eq $_[1]) {
54        print "ok $test$comment\n";
55        return 1;
56    } else {
57      $comment .= ": '$_[0]' ne '$_[1]'";
58        print "not ok $test$comment\n";
59        return 0;
60    }
61  } else {
62    if (shift) {
63        print "ok $test\n";
64        return 1;
65    } else {
66      print "not ok $test\n";
67        return 0;
68    }
69  }
70}
71
72$a = new Oscalar "087";
73$b= "$a";
74
75# All test numbers in comments are off by 1.
76# So much for hard-wiring them in :-) To fix this:
77test(1);			# 1
78
79test ($b eq $a);		# 2
80test ($b eq "087");		# 3
81test (ref $a eq "Oscalar");	# 4
82test ($a eq $a);		# 5
83test ($a eq "087");		# 6
84
85$c = $a + 7;
86
87test (ref $c eq "Oscalar");	# 7
88test (!($c eq $a));		# 8
89test ($c eq "94");		# 9
90
91$b=$a;
92
93test (ref $a eq "Oscalar");	# 10
94
95$b++;
96
97test (ref $b eq "Oscalar");	# 11
98test ( $a eq "087");		# 12
99test ( $b eq "88");		# 13
100test (ref $a eq "Oscalar");	# 14
101
102$c=$b;
103$c-=$a;
104
105test (ref $c eq "Oscalar");	# 15
106test ( $a eq "087");		# 16
107test ( $c eq "1");		# 17
108test (ref $a eq "Oscalar");	# 18
109
110$b=1;
111$b+=$a;
112
113test (ref $b eq "Oscalar");	# 19
114test ( $a eq "087");		# 20
115test ( $b eq "88");		# 21
116test (ref $a eq "Oscalar");	# 22
117
118eval q[ package Oscalar; use overload ('++' => sub { $ {$_[0]}++;$_[0] } ) ];
119
120$b=$a;
121
122test (ref $a eq "Oscalar");	# 23
123
124$b++;
125
126test (ref $b eq "Oscalar");	# 24
127test ( $a eq "087");		# 25
128test ( $b eq "88");		# 26
129test (ref $a eq "Oscalar");	# 27
130
131package Oscalar;
132$dummy=bless \$dummy;		# Now cache of method should be reloaded
133package main;
134
135$b=$a;
136$b++;
137
138test (ref $b eq "Oscalar");	# 28
139test ( $a eq "087");		# 29
140test ( $b eq "88");		# 30
141test (ref $a eq "Oscalar");	# 31
142
143undef $b;			# Destroying updates tables too...
144
145eval q[package Oscalar; use overload ('++' => sub { $ {$_[0]} += 2; $_[0] } ) ];
146
147$b=$a;
148
149test (ref $a eq "Oscalar");	# 32
150
151$b++;
152
153test (ref $b eq "Oscalar");	# 33
154test ( $a eq "087");		# 34
155test ( $b eq "88");		# 35
156test (ref $a eq "Oscalar");	# 36
157
158package Oscalar;
159$dummy=bless \$dummy;		# Now cache of method should be reloaded
160package main;
161
162$b++;
163
164test (ref $b eq "Oscalar");	# 37
165test ( $a eq "087");		# 38
166test ( $b eq "90");		# 39
167test (ref $a eq "Oscalar");	# 40
168
169$b=$a;
170$b++;
171
172test (ref $b eq "Oscalar");	# 41
173test ( $a eq "087");		# 42
174test ( $b eq "89");		# 43
175test (ref $a eq "Oscalar");	# 44
176
177
178test ($b? 1:0);			# 45
179
180eval q[ package Oscalar; use overload ('=' => sub {$main::copies++;
181						   package Oscalar;
182						   local $new=$ {$_[0]};
183						   bless \$new } ) ];
184
185$b=new Oscalar "$a";
186
187test (ref $b eq "Oscalar");	# 46
188test ( $a eq "087");		# 47
189test ( $b eq "087");		# 48
190test (ref $a eq "Oscalar");	# 49
191
192$b++;
193
194test (ref $b eq "Oscalar");	# 50
195test ( $a eq "087");		# 51
196test ( $b eq "89");		# 52
197test (ref $a eq "Oscalar");	# 53
198test ($copies == 0);		# 54
199
200$b+=1;
201
202test (ref $b eq "Oscalar");	# 55
203test ( $a eq "087");		# 56
204test ( $b eq "90");		# 57
205test (ref $a eq "Oscalar");	# 58
206test ($copies == 0);		# 59
207
208$b=$a;
209$b+=1;
210
211test (ref $b eq "Oscalar");	# 60
212test ( $a eq "087");		# 61
213test ( $b eq "88");		# 62
214test (ref $a eq "Oscalar");	# 63
215test ($copies == 0);		# 64
216
217$b=$a;
218$b++;
219
220test (ref $b eq "Oscalar") || print ref $b,"=ref(b)\n";	# 65
221test ( $a eq "087");		# 66
222test ( $b eq "89");		# 67
223test (ref $a eq "Oscalar");	# 68
224test ($copies == 1);		# 69
225
226eval q[package Oscalar; use overload ('+=' => sub {$ {$_[0]} += 3*$_[1];
227						   $_[0] } ) ];
228$c=new Oscalar;			# Cause rehash
229
230$b=$a;
231$b+=1;
232
233test (ref $b eq "Oscalar");	# 70
234test ( $a eq "087");		# 71
235test ( $b eq "90");		# 72
236test (ref $a eq "Oscalar");	# 73
237test ($copies == 2);		# 74
238
239$b+=$b;
240
241test (ref $b eq "Oscalar");	# 75
242test ( $b eq "360");		# 76
243test ($copies == 2);		# 77
244$b=-$b;
245
246test (ref $b eq "Oscalar");	# 78
247test ( $b eq "-360");		# 79
248test ($copies == 2);		# 80
249
250$b=abs($b);
251
252test (ref $b eq "Oscalar");	# 81
253test ( $b eq "360");		# 82
254test ($copies == 2);		# 83
255
256$b=abs($b);
257
258test (ref $b eq "Oscalar");	# 84
259test ( $b eq "360");		# 85
260test ($copies == 2);		# 86
261
262eval q[package Oscalar;
263       use overload ('x' => sub {new Oscalar ( $_[2] ? "_.$_[1]._" x $ {$_[0]}
264					      : "_.${$_[0]}._" x $_[1])}) ];
265
266$a=new Oscalar "yy";
267$a x= 3;
268test ($a eq "_.yy.__.yy.__.yy._"); # 87
269
270eval q[package Oscalar;
271       use overload ('.' => sub {new Oscalar ( $_[2] ?
272					      "_.$_[1].__.$ {$_[0]}._"
273					      : "_.$ {$_[0]}.__.$_[1]._")}) ];
274
275$a=new Oscalar "xx";
276
277test ("b${a}c" eq "_._.b.__.xx._.__.c._"); # 88
278
279# Check inheritance of overloading;
280{
281  package OscalarI;
282  @ISA = 'Oscalar';
283}
284
285$aI = new OscalarI "$a";
286test (ref $aI eq "OscalarI");	# 89
287test ("$aI" eq "xx");		# 90
288test ($aI eq "xx");		# 91
289test ("b${aI}c" eq "_._.b.__.xx._.__.c._");		# 92
290
291# Here we test blessing to a package updates hash
292
293eval "package Oscalar; no overload '.'";
294
295test ("b${a}" eq "_.b.__.xx._"); # 93
296$x="1";
297bless \$x, Oscalar;
298test ("b${a}c" eq "bxxc");	# 94
299new Oscalar 1;
300test ("b${a}c" eq "bxxc");	# 95
301
302# Negative overloading:
303
304$na = eval { ~$a };
305test($@ =~ /no method found/);	# 96
306
307# Check AUTOLOADING:
308
309*Oscalar::AUTOLOAD =
310  sub { *{"Oscalar::$AUTOLOAD"} = sub {"_!_" . shift() . "_!_"} ;
311	goto &{"Oscalar::$AUTOLOAD"}};
312
313eval "package Oscalar; sub comple; use overload '~' => 'comple'";
314
315$na = eval { ~$a };		# Hash was not updated
316test($@ =~ /no method found/);	# 97
317
318bless \$x, Oscalar;
319
320$na = eval { ~$a };		# Hash updated
321warn "`$na', $@" if $@;
322test !$@;			# 98
323test($na eq '_!_xx_!_');	# 99
324
325$na = 0;
326
327$na = eval { ~$aI };		# Hash was not updated
328test($@ =~ /no method found/);	# 100
329
330bless \$x, OscalarI;
331
332$na = eval { ~$aI };
333print $@;
334
335test !$@;			# 101
336test($na eq '_!_xx_!_');	# 102
337
338eval "package Oscalar; sub rshft; use overload '>>' => 'rshft'";
339
340$na = eval { $aI >> 1 };	# Hash was not updated
341test($@ =~ /no method found/);	# 103
342
343bless \$x, OscalarI;
344
345$na = 0;
346
347$na = eval { $aI >> 1 };
348print $@;
349
350test !$@;			# 104
351test($na eq '_!_xx_!_');	# 105
352
353# warn overload::Method($a, '0+'), "\n";
354test (overload::Method($a, '0+') eq \&Oscalar::numify); # 106
355test (overload::Method($aI,'0+') eq \&Oscalar::numify); # 107
356test (overload::Overloaded($aI)); # 108
357test (!overload::Overloaded('overload')); # 109
358
359test (! defined overload::Method($aI, '<<')); # 110
360test (! defined overload::Method($a, '<')); # 111
361
362test (overload::StrVal($aI) =~ /^OscalarI=SCALAR\(0x[\da-fA-F]+\)$/); # 112
363test (overload::StrVal(\$aI) eq "@{[\$aI]}"); # 113
364
365# Check overloading by methods (specified deep in the ISA tree).
366{
367  package OscalarII;
368  @ISA = 'OscalarI';
369  sub Oscalar::lshft {"_<<_" . shift() . "_<<_"}
370  eval "package OscalarI; use overload '<<' => 'lshft', '|' => 'lshft'";
371}
372
373$aaII = "087";
374$aII = \$aaII;
375bless $aII, 'OscalarII';
376bless \$fake, 'OscalarI';		# update the hash
377test(($aI | 3) eq '_<<_xx_<<_');	# 114
378# warn $aII << 3;
379test(($aII << 3) eq '_<<_087_<<_');	# 115
380
381{
382  BEGIN { $int = 7; overload::constant 'integer' => sub {$int++; shift}; }
383  $out = 2**10;
384}
385test($int, 9);		# 116
386test($out, 1024);		# 117
387
388$foo = 'foo';
389$foo1 = 'f\'o\\o';
390{
391  BEGIN { $q = $qr = 7; 
392	  overload::constant 'q' => sub {$q++; push @q, shift, ($_[1] || 'none'); shift},
393			     'qr' => sub {$qr++; push @qr, shift, ($_[1] || 'none'); shift}; }
394  $out = 'foo';
395  $out1 = 'f\'o\\o';
396  $out2 = "a\a$foo,\,";
397  /b\b$foo.\./;
398}
399
400test($out, 'foo');		# 118
401test($out, $foo);		# 119
402test($out1, 'f\'o\\o');		# 120
403test($out1, $foo1);		# 121
404test($out2, "a\afoo,\,");	# 122
405test("@q", "foo q f'o\\\\o q a\\a qq ,\\, qq");	# 123
406test($q, 11);			# 124
407test("@qr", "b\\b qq .\\. qq");	# 125
408test($qr, 9);			# 126
409
410{
411  $_ = '!<b>!foo!<-.>!';
412  BEGIN { overload::constant 'q' => sub {push @q1, shift, ($_[1] || 'none'); "_<" . (shift) . ">_"},
413			     'qr' => sub {push @qr1, shift, ($_[1] || 'none'); "!<" . (shift) . ">!"}; }
414  $out = 'foo';
415  $out1 = 'f\'o\\o';
416  $out2 = "a\a$foo,\,";
417  $res = /b\b$foo.\./;
418  $a = <<EOF;
419oups
420EOF
421  $b = <<'EOF';
422oups1
423EOF
424  $c = bareword;
425  m'try it';
426  s'first part'second part';
427  s/yet another/tail here/;
428  tr/A-Z/a-z/;
429}
430
431test($out, '_<foo>_');		# 117
432test($out1, '_<f\'o\\o>_');		# 128
433test($out2, "_<a\a>_foo_<,\,>_");	# 129
434test("@q1", "foo q f'o\\\\o q a\\a qq ,\\, qq oups
435 qq oups1
436 q second part q tail here s A-Z tr a-z tr");	# 130
437test("@qr1", "b\\b qq .\\. qq try it q first part q yet another qq");	# 131
438test($res, 1);			# 132
439test($a, "_<oups
440>_");	# 133
441test($b, "_<oups1
442>_");	# 134
443test($c, "bareword");	# 135
444
445{
446  package symbolic;		# Primitive symbolic calculator
447  use overload nomethod => \&wrap, '""' => \&str, '0+' => \&num,
448      '=' => \&cpy, '++' => \&inc, '--' => \&dec;
449
450  sub new { shift; bless ['n', @_] }
451  sub cpy {
452    my $self = shift;
453    bless [@$self], ref $self;
454  }
455  sub inc { $_[0] = bless ['++', $_[0], 1]; }
456  sub dec { $_[0] = bless ['--', $_[0], 1]; }
457  sub wrap {
458    my ($obj, $other, $inv, $meth) = @_;
459    if ($meth eq '++' or $meth eq '--') {
460      @$obj = ($meth, (bless [@$obj]), 1); # Avoid circular reference
461      return $obj;
462    }
463    ($obj, $other) = ($other, $obj) if $inv;
464    bless [$meth, $obj, $other];
465  }
466  sub str {
467    my ($meth, $a, $b) = @{+shift};
468    $a = 'u' unless defined $a;
469    if (defined $b) {
470      "[$meth $a $b]";
471    } else {
472      "[$meth $a]";
473    }
474  } 
475  my %subr = ( 'n' => sub {$_[0]} );
476  foreach my $op (split " ", $overload::ops{with_assign}) {
477    $subr{$op} = $subr{"$op="} = eval "sub {shift() $op shift()}";
478  }
479  my @bins = qw(binary 3way_comparison num_comparison str_comparison);
480  foreach my $op (split " ", "@overload::ops{ @bins }") {
481    $subr{$op} = eval "sub {shift() $op shift()}";
482  }
483  foreach my $op (split " ", "@overload::ops{qw(unary func)}") {
484    $subr{$op} = eval "sub {$op shift()}";
485  }
486  $subr{'++'} = $subr{'+'};
487  $subr{'--'} = $subr{'-'};
488  
489  sub num {
490    my ($meth, $a, $b) = @{+shift};
491    my $subr = $subr{$meth} 
492      or die "Do not know how to ($meth) in symbolic";
493    $a = $a->num if ref $a eq __PACKAGE__;
494    $b = $b->num if ref $b eq __PACKAGE__;
495    $subr->($a,$b);
496  }
497  sub TIESCALAR { my $pack = shift; $pack->new(@_) }
498  sub FETCH { shift }
499  sub nop {  }		# Around a bug
500  sub vars { my $p = shift; tie($_, $p), $_->nop foreach @_; }
501  sub STORE { 
502    my $obj = shift; 
503    $#$obj = 1; 
504    $obj->[1] = shift;
505  }
506}
507
508{
509  my $foo = new symbolic 11;
510  my $baz = $foo++;
511  test( (sprintf "%d", $foo), '12');
512  test( (sprintf "%d", $baz), '11');
513  my $bar = $foo;
514  $baz = ++$foo;
515  test( (sprintf "%d", $foo), '13');
516  test( (sprintf "%d", $bar), '12');
517  test( (sprintf "%d", $baz), '13');
518  my $ban = $foo;
519  $baz = ($foo += 1);
520  test( (sprintf "%d", $foo), '14');
521  test( (sprintf "%d", $bar), '12');
522  test( (sprintf "%d", $baz), '14');
523  test( (sprintf "%d", $ban), '13');
524  $baz = 0;
525  $baz = $foo++;
526  test( (sprintf "%d", $foo), '15');
527  test( (sprintf "%d", $baz), '14');
528  test( "$foo", '[++ [+= [++ [++ [n 11] 1] 1] 1] 1]');
529}
530
531{
532  my $iter = new symbolic 2;
533  my $side = new symbolic 1;
534  my $cnt = $iter;
535  
536  while ($cnt) {
537    $cnt = $cnt - 1;		# The "simple" way
538    $side = (sqrt(1 + $side**2) - 1)/$side;
539  }
540  my $pi = $side*(2**($iter+2));
541  test "$side", '[/ [- [sqrt [+ 1 [** [/ [- [sqrt [+ 1 [** [n 1] 2]]] 1] [n 1]] 2]]] 1] [/ [- [sqrt [+ 1 [** [n 1] 2]]] 1] [n 1]]]';
542  test( (sprintf "%f", $pi), '3.182598');
543}
544
545{
546  my $iter = new symbolic 2;
547  my $side = new symbolic 1;
548  my $cnt = $iter;
549  
550  while ($cnt--) {
551    $side = (sqrt(1 + $side**2) - 1)/$side;
552  }
553  my $pi = $side*(2**($iter+2));
554  test "$side", '[/ [- [sqrt [+ 1 [** [/ [- [sqrt [+ 1 [** [n 1] 2]]] 1] [n 1]] 2]]] 1] [/ [- [sqrt [+ 1 [** [n 1] 2]]] 1] [n 1]]]';
555  test( (sprintf "%f", $pi), '3.182598');
556}
557
558{
559  my ($a, $b);
560  symbolic->vars($a, $b);
561  my $c = sqrt($a**2 + $b**2);
562  $a = 3; $b = 4;
563  test( (sprintf "%d", $c), '5');
564  $a = 12; $b = 5;
565  test( (sprintf "%d", $c), '13');
566}
567
568{
569  package symbolic1;		# Primitive symbolic calculator
570  # Mutator inc/dec
571  use overload nomethod => \&wrap, '""' => \&str, '0+' => \&num, '=' => \&cpy;
572
573  sub new { shift; bless ['n', @_] }
574  sub cpy {
575    my $self = shift;
576    bless [@$self], ref $self;
577  }
578  sub wrap {
579    my ($obj, $other, $inv, $meth) = @_;
580    if ($meth eq '++' or $meth eq '--') {
581      @$obj = ($meth, (bless [@$obj]), 1); # Avoid circular reference
582      return $obj;
583    }
584    ($obj, $other) = ($other, $obj) if $inv;
585    bless [$meth, $obj, $other];
586  }
587  sub str {
588    my ($meth, $a, $b) = @{+shift};
589    $a = 'u' unless defined $a;
590    if (defined $b) {
591      "[$meth $a $b]";
592    } else {
593      "[$meth $a]";
594    }
595  } 
596  my %subr = ( 'n' => sub {$_[0]} );
597  foreach my $op (split " ", $overload::ops{with_assign}) {
598    $subr{$op} = $subr{"$op="} = eval "sub {shift() $op shift()}";
599  }
600  my @bins = qw(binary 3way_comparison num_comparison str_comparison);
601  foreach my $op (split " ", "@overload::ops{ @bins }") {
602    $subr{$op} = eval "sub {shift() $op shift()}";
603  }
604  foreach my $op (split " ", "@overload::ops{qw(unary func)}") {
605    $subr{$op} = eval "sub {$op shift()}";
606  }
607  $subr{'++'} = $subr{'+'};
608  $subr{'--'} = $subr{'-'};
609  
610  sub num {
611    my ($meth, $a, $b) = @{+shift};
612    my $subr = $subr{$meth} 
613      or die "Do not know how to ($meth) in symbolic";
614    $a = $a->num if ref $a eq __PACKAGE__;
615    $b = $b->num if ref $b eq __PACKAGE__;
616    $subr->($a,$b);
617  }
618  sub TIESCALAR { my $pack = shift; $pack->new(@_) }
619  sub FETCH { shift }
620  sub nop {  }		# Around a bug
621  sub vars { my $p = shift; tie($_, $p), $_->nop foreach @_; }
622  sub STORE { 
623    my $obj = shift; 
624    $#$obj = 1; 
625    $obj->[1] = shift;
626  }
627}
628
629{
630  my $foo = new symbolic1 11;
631  my $baz = $foo++;
632  test( (sprintf "%d", $foo), '12');
633  test( (sprintf "%d", $baz), '11');
634  my $bar = $foo;
635  $baz = ++$foo;
636  test( (sprintf "%d", $foo), '13');
637  test( (sprintf "%d", $bar), '12');
638  test( (sprintf "%d", $baz), '13');
639  my $ban = $foo;
640  $baz = ($foo += 1);
641  test( (sprintf "%d", $foo), '14');
642  test( (sprintf "%d", $bar), '12');
643  test( (sprintf "%d", $baz), '14');
644  test( (sprintf "%d", $ban), '13');
645  $baz = 0;
646  $baz = $foo++;
647  test( (sprintf "%d", $foo), '15');
648  test( (sprintf "%d", $baz), '14');
649  test( "$foo", '[++ [+= [++ [++ [n 11] 1] 1] 1] 1]');
650}
651
652{
653  my $iter = new symbolic1 2;
654  my $side = new symbolic1 1;
655  my $cnt = $iter;
656  
657  while ($cnt) {
658    $cnt = $cnt - 1;		# The "simple" way
659    $side = (sqrt(1 + $side**2) - 1)/$side;
660  }
661  my $pi = $side*(2**($iter+2));
662  test "$side", '[/ [- [sqrt [+ 1 [** [/ [- [sqrt [+ 1 [** [n 1] 2]]] 1] [n 1]] 2]]] 1] [/ [- [sqrt [+ 1 [** [n 1] 2]]] 1] [n 1]]]';
663  test( (sprintf "%f", $pi), '3.182598');
664}
665
666{
667  my $iter = new symbolic1 2;
668  my $side = new symbolic1 1;
669  my $cnt = $iter;
670  
671  while ($cnt--) {
672    $side = (sqrt(1 + $side**2) - 1)/$side;
673  }
674  my $pi = $side*(2**($iter+2));
675  test "$side", '[/ [- [sqrt [+ 1 [** [/ [- [sqrt [+ 1 [** [n 1] 2]]] 1] [n 1]] 2]]] 1] [/ [- [sqrt [+ 1 [** [n 1] 2]]] 1] [n 1]]]';
676  test( (sprintf "%f", $pi), '3.182598');
677}
678
679{
680  my ($a, $b);
681  symbolic1->vars($a, $b);
682  my $c = sqrt($a**2 + $b**2);
683  $a = 3; $b = 4;
684  test( (sprintf "%d", $c), '5');
685  $a = 12; $b = 5;
686  test( (sprintf "%d", $c), '13');
687}
688
689{
690  package two_face;		# Scalars with separate string and
691                                # numeric values.
692  sub new { my $p = shift; bless [@_], $p }
693  use overload '""' => \&str, '0+' => \&num, fallback => 1;
694  sub num {shift->[1]}
695  sub str {shift->[0]}
696}
697
698{
699  my $seven = new two_face ("vii", 7);
700  test( (sprintf "seven=$seven, seven=%d, eight=%d", $seven, $seven+1),
701	'seven=vii, seven=7, eight=8');
702  test( scalar ($seven =~ /i/), '1')
703}
704
705{
706  package sorting;
707  use overload 'cmp' => \&comp;
708  sub new { my ($p, $v) = @_; bless \$v, $p }
709  sub comp { my ($x,$y) = @_; ($$x * 3 % 10) <=> ($$y * 3 % 10) or $$x cmp $$y }
710}
711{
712  my @arr = map sorting->new($_), 0..12;
713  my @sorted1 = sort @arr;
714  my @sorted2 = map $$_, @sorted1;
715  test "@sorted2", '0 10 7 4 1 11 8 5 12 2 9 6 3';
716}
717{
718  package iterator;
719  use overload '<>' => \&iter;
720  sub new { my ($p, $v) = @_; bless \$v, $p }
721  sub iter { my ($x) = @_; return undef if $$x < 0; return $$x--; }
722}
723
724# XXX iterator overload not intended to work with CORE::GLOBAL?
725if (defined &CORE::GLOBAL::glob) {
726  test '1', '1';	# 175
727  test '1', '1';	# 176
728  test '1', '1';	# 177
729}
730else {
731  my $iter = iterator->new(5);
732  my $acc = '';
733  my $out;
734  $acc .= " $out" while $out = <${iter}>;
735  test $acc, ' 5 4 3 2 1 0';	# 175
736  $iter = iterator->new(5);
737  test scalar <${iter}>, '5';	# 176
738  $acc = '';
739  $acc .= " $out" while $out = <$iter>;
740  test $acc, ' 4 3 2 1 0';	# 177
741}
742{
743  package deref;
744  use overload '%{}' => \&hderef, '&{}' => \&cderef, 
745    '*{}' => \&gderef, '${}' => \&sderef, '@{}' => \&aderef;
746  sub new { my ($p, $v) = @_; bless \$v, $p }
747  sub deref {
748    my ($self, $key) = (shift, shift);
749    my $class = ref $self;
750    bless $self, 'deref::dummy'; # Disable overloading of %{} 
751    my $out = $self->{$key};
752    bless $self, $class;	# Restore overloading
753    $out;
754  }
755  sub hderef {shift->deref('h')}
756  sub aderef {shift->deref('a')}
757  sub cderef {shift->deref('c')}
758  sub gderef {shift->deref('g')}
759  sub sderef {shift->deref('s')}
760}
761{
762  my $deref = bless { h => { foo => 5 , fake => 23 },
763		      c => sub {return shift() + 34},
764		      's' => \123,
765		      a => [11..13],
766		      g => \*srt,
767		    }, 'deref';
768  # Hash:
769  my @cont = sort %$deref;
770  if ("\t" eq "\011") { # ascii
771      test "@cont", '23 5 fake foo';	# 178
772  } 
773  else {                # ebcdic alpha-numeric sort order
774      test "@cont", 'fake foo 23 5';	# 178
775  }
776  my @keys = sort keys %$deref;
777  test "@keys", 'fake foo';	# 179
778  my @val = sort values %$deref;
779  test "@val", '23 5';		# 180
780  test $deref->{foo}, 5;	# 181
781  test defined $deref->{bar}, ''; # 182
782  my $key;
783  @keys = ();
784  push @keys, $key while $key = each %$deref;
785  @keys = sort @keys;
786  test "@keys", 'fake foo';	# 183  
787  test exists $deref->{bar}, ''; # 184
788  test exists $deref->{foo}, 1; # 185
789  # Code:
790  test $deref->(5), 39;		# 186
791  test &$deref(6), 40;		# 187
792  sub xxx_goto { goto &$deref }
793  test xxx_goto(7), 41;		# 188
794  my $srt = bless { c => sub {$b <=> $a}
795		  }, 'deref';
796  *srt = \&$srt;
797  my @sorted = sort srt 11, 2, 5, 1, 22;
798  test "@sorted", '22 11 5 2 1'; # 189
799  # Scalar
800  test $$deref, 123;		# 190
801  # Code
802  @sorted = sort $srt 11, 2, 5, 1, 22;
803  test "@sorted", '22 11 5 2 1'; # 191
804  # Array
805  test "@$deref", '11 12 13';	# 192
806  test $#$deref, '2';		# 193
807  my $l = @$deref;
808  test $l, 3;			# 194
809  test $deref->[2], '13';		# 195
810  $l = pop @$deref;
811  test $l, 13;			# 196
812  $l = 1;
813  test $deref->[$l], '12';	# 197
814  # Repeated dereference
815  my $double = bless { h => $deref,
816		     }, 'deref';
817  test $double->{foo}, 5;	# 198
818}
819
820{
821  package two_refs;
822  use overload '%{}' => \&gethash, '@{}' => sub { ${shift()} };
823  sub new { 
824    my $p = shift; 
825    bless \ [@_], $p;
826  }
827  sub gethash {
828    my %h;
829    my $self = shift;
830    tie %h, ref $self, $self;
831    \%h;
832  }
833
834  sub TIEHASH { my $p = shift; bless \ shift, $p }
835  my %fields;
836  my $i = 0;
837  $fields{$_} = $i++ foreach qw{zero one two three};
838  sub STORE { 
839    my $self = ${shift()};
840    my $key = $fields{shift()};
841    defined $key or die "Out of band access";
842    $$self->[$key] = shift;
843  }
844  sub FETCH { 
845    my $self = ${shift()};
846    my $key = $fields{shift()};
847    defined $key or die "Out of band access";
848    $$self->[$key];
849  }
850}
851
852my $bar = new two_refs 3,4,5,6;
853$bar->[2] = 11;
854test $bar->{two}, 11;		# 199
855$bar->{three} = 13;
856test $bar->[3], 13;		# 200
857
858{
859  package two_refs_o;
860  @ISA = ('two_refs');
861}
862
863$bar = new two_refs_o 3,4,5,6;
864$bar->[2] = 11;
865test $bar->{two}, 11;		# 201
866$bar->{three} = 13;
867test $bar->[3], 13;		# 202
868
869{
870  package two_refs1;
871  use overload '%{}' => sub { ${shift()}->[1] },
872               '@{}' => sub { ${shift()}->[0] };
873  sub new { 
874    my $p = shift; 
875    my $a = [@_];
876    my %h;
877    tie %h, $p, $a;
878    bless \ [$a, \%h], $p;
879  }
880  sub gethash {
881    my %h;
882    my $self = shift;
883    tie %h, ref $self, $self;
884    \%h;
885  }
886
887  sub TIEHASH { my $p = shift; bless \ shift, $p }
888  my %fields;
889  my $i = 0;
890  $fields{$_} = $i++ foreach qw{zero one two three};
891  sub STORE { 
892    my $a = ${shift()};
893    my $key = $fields{shift()};
894    defined $key or die "Out of band access";
895    $a->[$key] = shift;
896  }
897  sub FETCH { 
898    my $a = ${shift()};
899    my $key = $fields{shift()};
900    defined $key or die "Out of band access";
901    $a->[$key];
902  }
903}
904
905$bar = new two_refs_o 3,4,5,6;
906$bar->[2] = 11;
907test $bar->{two}, 11;		# 203
908$bar->{three} = 13;
909test $bar->[3], 13;		# 204
910
911{
912  package two_refs1_o;
913  @ISA = ('two_refs1');
914}
915
916$bar = new two_refs1_o 3,4,5,6;
917$bar->[2] = 11;
918test $bar->{two}, 11;		# 205
919$bar->{three} = 13;
920test $bar->[3], 13;		# 206
921
922{
923  package B;
924  use overload bool => sub { ${+shift} };
925}
926
927my $aaa;
928{ my $bbbb = 0; $aaa = bless \$bbbb, B }
929
930test !$aaa, 1;			# 207
931
932unless ($aaa) {
933  test 'ok', 'ok';		# 208
934} else {
935  test 'is not', 'ok';		# 208
936}
937
938# check that overload isn't done twice by join
939{ my $c = 0;
940  package Join;
941  use overload '""' => sub { $c++ };
942  my $x = join '', bless([]), 'pq', bless([]);
943  main::test $x, '0pq1';		# 209
944};
945
946# Test module-specific warning
947{
948    # check the Odd number of arguments for overload::constant warning
949    my $a = "" ;
950    local $SIG{__WARN__} = sub {$a = $_[0]} ;
951    $x = eval ' overload::constant "integer" ; ' ;
952    test($a eq "") ; # 210
953    use warnings 'overload' ;
954    $x = eval ' overload::constant "integer" ; ' ;
955    test($a =~ /^Odd number of arguments for overload::constant at/) ; # 211
956}
957
958{
959    # check the `$_[0]' is not an overloadable type warning
960    my $a = "" ;
961    local $SIG{__WARN__} = sub {$a = $_[0]} ;
962    $x = eval ' overload::constant "fred" => sub {} ; ' ;
963    test($a eq "") ; # 212
964    use warnings 'overload' ;
965    $x = eval ' overload::constant "fred" => sub {} ; ' ;
966    test($a =~ /^`fred' is not an overloadable type at/); # 213
967}
968
969{
970    # check the `$_[1]' is not a code reference warning
971    my $a = "" ;
972    local $SIG{__WARN__} = sub {$a = $_[0]} ;
973    $x = eval ' overload::constant "integer" => 1; ' ;
974    test($a eq "") ; # 214
975    use warnings 'overload' ;
976    $x = eval ' overload::constant "integer" => 1; ' ;
977    test($a =~ /^`1' is not a code reference at/); # 215
978}
979
980{
981  my $c = 0;
982  package ov_int1;
983  use overload '""'    => sub { 3+shift->[0] },
984               '0+'    => sub { 10+shift->[0] },
985               'int'   => sub { 100+shift->[0] };
986  sub new {my $p = shift; bless [shift], $p}
987
988  package ov_int2;
989  use overload '""'    => sub { 5+shift->[0] },
990               '0+'    => sub { 30+shift->[0] },
991               'int'   => sub { 'ov_int1'->new(1000+shift->[0]) };
992  sub new {my $p = shift; bless [shift], $p}
993
994  package noov_int;
995  use overload '""'    => sub { 2+shift->[0] },
996               '0+'    => sub { 9+shift->[0] };
997  sub new {my $p = shift; bless [shift], $p}
998
999  package main;
1000
1001  my $x = new noov_int 11;
1002  my $int_x = int $x;
1003  main::test("$int_x" eq 20);			# 216
1004  $x = new ov_int1 31;
1005  $int_x = int $x;
1006  main::test("$int_x" eq 131);			# 217
1007  $x = new ov_int2 51;
1008  $int_x = int $x;
1009  main::test("$int_x" eq 1054);			# 218
1010}
1011
1012# make sure that we don't inifinitely recurse
1013{
1014  my $c = 0;
1015  package Recurse;
1016  use overload '""'    => sub { shift },
1017               '0+'    => sub { shift },
1018               'bool'  => sub { shift },
1019               fallback => 1;
1020  my $x = bless([]);
1021  main::test("$x" =~ /Recurse=ARRAY/);		# 219
1022  main::test($x);                               # 220
1023  main::test($x+0 =~ /Recurse=ARRAY/);		# 221
1024}
1025
1026# BugID 20010422.003
1027package Foo;
1028
1029use overload
1030  'bool' => sub { return !$_[0]->is_zero() || undef; }
1031;
1032 
1033sub is_zero
1034  {
1035  my $self = shift;
1036  return $self->{var} == 0;
1037  }
1038
1039sub new
1040  {
1041  my $class = shift;
1042  my $self =  {};
1043  $self->{var} = shift;
1044  bless $self,$class;
1045  }
1046
1047package main;
1048
1049use strict;
1050
1051my $r = Foo->new(8);
1052$r = Foo->new(0);
1053
1054test(($r || 0) == 0); # 222
1055
1056package utf8_o;
1057
1058use overload 
1059  '""'  =>  sub { return $_[0]->{var}; }
1060  ;
1061  
1062sub new
1063  {
1064    my $class = shift;
1065    my $self =  {};
1066    $self->{var} = shift;
1067    bless $self,$class;
1068  }
1069
1070package main;
1071
1072
1073my $utfvar = new utf8_o 200.2.1;
1074test("$utfvar" eq 200.2.1); # 223 - stringify
1075test("a$utfvar" eq "a".200.2.1); # 224 - overload via sv_2pv_flags
1076
1077# 225..227 -- more %{} tests.  Hangs in 5.6.0, okay in later releases.
1078# Basically this example implements strong encapsulation: if Hderef::import()
1079# were to eval the overload code in the caller's namespace, the privatisation
1080# would be quite transparent.
1081package Hderef;
1082use overload '%{}' => sub { (caller(0))[0] eq 'Foo' ? $_[0] : die "zap" };
1083package Foo;
1084@Foo::ISA = 'Hderef';
1085sub new { bless {}, shift }
1086sub xet { @_ == 2 ? $_[0]->{$_[1]} :
1087	  @_ == 3 ? ($_[0]->{$_[1]} = $_[2]) : undef }
1088package main;
1089my $a = Foo->new;
1090$a->xet('b', 42);
1091print $a->xet('b') == 42 ? "ok 225\n" : "not ok 225\n";
1092print defined eval { $a->{b} } ? "not ok 226\n" : "ok 226\n";
1093print $@ =~ /zap/ ? "ok 227\n" : "not ok 227\n";
1094
1095print overload::StrVal(qr/a/) =~ /^Regexp=SCALAR\(0x[0-9a-f]+\)$/ ? "ok 228\n" : "not ok 228\n";
1096
1097{
1098   package t229;
1099   use overload '='  => sub { 42 },
1100                '++' => sub { my $x = ${$_[0]}; $_[0] };
1101   sub new { my $x = 42; bless \$x }
1102
1103   my $warn;
1104   {  
1105     local $SIG{__WARN__} = sub { $warn++ };
1106      my $x = t229->new;
1107      my $y = $x;
1108      eval { $y++ };
1109   }
1110   print $warn ? "not ok 229\n" : "ok 229\n";
1111}
1112
1113{
1114    package Numify;
1115    use overload (qw(0+ numify fallback 1));
1116
1117    sub new {
1118        my $val = $_[1];
1119        bless \$val, $_[0];
1120    }
1121
1122    sub numify { ${$_[0]} }
1123}
1124
1125# These are all check that overloaded values rather than reference addressess
1126# are what is getting tested.
1127my ($two, $one, $un, $deux) = map {new Numify $_} 2, 1, 1, 2;
1128my ($ein, $zwei) = (1, 2);
1129
1130my %map = (one => 1, un => 1, ein => 1, deux => 2, two => 2, zwei => 2);
1131foreach my $op (qw(<=> == != < <= > >=)) {
1132    foreach my $l (keys %map) {
1133        foreach my $r (keys %map) {
1134            my $ocode = "\$$l $op \$$r";
1135            my $rcode = "$map{$l} $op $map{$r}";
1136
1137            my $got = eval $ocode;
1138            die if $@;
1139            my $expect = eval $rcode;
1140            die if $@;
1141            test ($got, $expect, $ocode) or print "# $rcode\n";
1142        }
1143    }
1144}
1145
1146# Last test is:
1147sub last {476}
1148