| 1 | use v6; |
|---|
| 2 | |
|---|
| 3 | use Test; |
|---|
| 4 | |
|---|
| 5 | =begin kwid |
|---|
| 6 | |
|---|
| 7 | Test basic escape continuations obtained from &?CALLER_CONTINUATION |
|---|
| 8 | |
|---|
| 9 | =end kwid |
|---|
| 10 | |
|---|
| 11 | plan 16; |
|---|
| 12 | |
|---|
| 13 | sub simple1() returns Int { |
|---|
| 14 | &?CALLER_CONTINUATION(2); |
|---|
| 15 | return 1; |
|---|
| 16 | } |
|---|
| 17 | is(simple1(), 2, 'using ec instead of return'); |
|---|
| 18 | |
|---|
| 19 | sub simple2(Num $n) { |
|---|
| 20 | if ($n == 5) { |
|---|
| 21 | &?CALLER_CONTINUATION(1); |
|---|
| 22 | } |
|---|
| 23 | return 0; |
|---|
| 24 | } |
|---|
| 25 | ok(simple2(5), 'ec used to escape ($n = 5)'); |
|---|
| 26 | ok(!simple2(1), 'ec not used'); |
|---|
| 27 | |
|---|
| 28 | sub closure1 () returns Int { |
|---|
| 29 | my $cont = &?CALLER_CONTINUATION; |
|---|
| 30 | my $a = sub { $cont(5) }; |
|---|
| 31 | $a(); |
|---|
| 32 | return 6; |
|---|
| 33 | } |
|---|
| 34 | is(closure1(), 5, 'closure uses ec to escape'); |
|---|
| 35 | |
|---|
| 36 | sub call_argument(Code $f, $arg) { |
|---|
| 37 | return $f($arg); |
|---|
| 38 | } |
|---|
| 39 | sub foo(Code $f) returns Int { |
|---|
| 40 | call_argument($f, 8); |
|---|
| 41 | return 3; |
|---|
| 42 | } |
|---|
| 43 | sub passing1 () returns Int { |
|---|
| 44 | foo(&?CALLER_CONTINUATION); |
|---|
| 45 | return 2; |
|---|
| 46 | } |
|---|
| 47 | is(try { passing1() }, 8, 'ec passed as an argument'); |
|---|
| 48 | |
|---|
| 49 | sub is_five(Num $n, Code $f) { |
|---|
| 50 | if ($n == 5) { |
|---|
| 51 | $f(1); |
|---|
| 52 | } |
|---|
| 53 | return 0; |
|---|
| 54 | } |
|---|
| 55 | sub passing2_not_cont(Num $n) { |
|---|
| 56 | my $a = 9; |
|---|
| 57 | is_five($n, sub { $a = 1 }); |
|---|
| 58 | return $a; |
|---|
| 59 | } |
|---|
| 60 | sub passing2(Num $n) { |
|---|
| 61 | is_five($n, &?CALLER_CONTINUATION); |
|---|
| 62 | return 9; |
|---|
| 63 | } |
|---|
| 64 | sub passing2_closure(Num $n) { |
|---|
| 65 | my $c = &?CALLER_CONTINUATION; |
|---|
| 66 | is_five($n, sub { $c(1) }); |
|---|
| 67 | return 9; |
|---|
| 68 | } |
|---|
| 69 | is(passing2_not_cont(5), 1, 'is_five w/o ec (1)'); |
|---|
| 70 | is(passing2_not_cont(2), 9, 'is_five w/o ec (2)'); |
|---|
| 71 | is(passing2(5), 1, 'is_five passing ec itself (1)'); |
|---|
| 72 | is(passing2(2), 9, 'is_five passing ec itself (2)'); |
|---|
| 73 | is(passing2_closure(5), 1, 'is_five passing ec via closure (1)'); |
|---|
| 74 | is(passing2_closure(2), 9, 'is_five passing ec via closure (2)'); |
|---|
| 75 | |
|---|
| 76 | sub callconty() { |
|---|
| 77 | conty(&?CALLER_CONTINUATION); |
|---|
| 78 | return 1; |
|---|
| 79 | } |
|---|
| 80 | sub conty(Code $c) { |
|---|
| 81 | $c(2); |
|---|
| 82 | return 3; |
|---|
| 83 | } |
|---|
| 84 | is(callconty(), 2, 'continuation bug'); |
|---|
| 85 | |
|---|
| 86 | # Now test complicated full continuations got from the same place. |
|---|
| 87 | |
|---|
| 88 | { |
|---|
| 89 | sub callcc (Code &block) { &block(&?CALLER_CONTINUATION) } |
|---|
| 90 | |
|---|
| 91 | my $cont; |
|---|
| 92 | my $counter = 0; |
|---|
| 93 | |
|---|
| 94 | callcc -> $cc { $cont = $cc }; |
|---|
| 95 | $counter++; |
|---|
| 96 | $cont(undef) unless $counter == 3; |
|---|
| 97 | is($counter, 3, "Looping with a full continuation"); |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | # Really evil: Store continuations in an aggregate |
|---|
| 101 | my $history; |
|---|
| 102 | my @expected = ( |
|---|
| 103 | "normalfoofoo0normalbarbar1", |
|---|
| 104 | "secondfoofoo2normalbarbar3", |
|---|
| 105 | "secondfoofoo2secondbarbar4", |
|---|
| 106 | ); |
|---|
| 107 | { |
|---|
| 108 | my %conts; |
|---|
| 109 | my $foo = sub { %conts<foo> = &?CALLER_CONTINUATION; return "normalfoo" }; |
|---|
| 110 | my $bar = sub { %conts<bar> = &?CALLER_CONTINUATION; return "normalbar" }; |
|---|
| 111 | |
|---|
| 112 | my $counter = 0; |
|---|
| 113 | |
|---|
| 114 | $history ~= $foo(); $history ~= "foo$counter"; $counter++; |
|---|
| 115 | $history ~= $bar(); $history ~= "bar$counter"; $counter++; |
|---|
| 116 | |
|---|
| 117 | is $history, @expected.shift, "continuations stored in an aggregate with loops"; |
|---|
| 118 | |
|---|
| 119 | %conts<foo>("secondfoo") if $counter <= 2; |
|---|
| 120 | %conts<bar>("secondbar") if $counter <= 4; |
|---|
| 121 | } |
|---|