| Filename | /home/hejohns/perl5/lib/perl5/Contextual/Return.pm |
| Statements | Executed 647 statements in 7.19ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 1.88ms | 2.21ms | Contextual::Return::BEGIN@361 |
| 2 | 2 | 2 | 518µs | 566µs | Contextual::Return::import (recurses: max depth 1, inclusive time 44µs) |
| 1 | 1 | 1 | 275µs | 293µs | Contextual::Return::BEGIN@252 |
| 61 | 12 | 10 | 200µs | 200µs | Contextual::Return::__ANON__[:30] |
| 1 | 1 | 1 | 23µs | 23µs | Contextual::Return::Value::BEGIN@1078 |
| 1 | 1 | 1 | 14µs | 14µs | Contextual::Return::BEGIN@12 |
| 1 | 1 | 1 | 12µs | 12µs | Contextual::Return::BEGIN@311 |
| 1 | 1 | 1 | 11µs | 21µs | Contextual::Return::Value::BEGIN@1426 |
| 7 | 1 | 1 | 10µs | 10µs | Contextual::Return::_add_exports_for |
| 1 | 1 | 1 | 8µs | 26µs | Contextual::Return::BEGIN@246 |
| 1 | 1 | 1 | 7µs | 16µs | Contextual::Return::BEGIN@589 |
| 1 | 1 | 1 | 6µs | 19µs | Contextual::Return::BEGIN@2 |
| 1 | 1 | 1 | 6µs | 7µs | Contextual::Return::BEGIN@3 |
| 1 | 1 | 1 | 6µs | 18µs | Contextual::Return::BEGIN@967 |
| 1 | 1 | 1 | 6µs | 10µs | Contextual::Return::BEGIN@809 |
| 1 | 1 | 1 | 6µs | 9µs | Contextual::Return::BEGIN@223 |
| 1 | 1 | 1 | 6µs | 10µs | Contextual::Return::BEGIN@670 |
| 1 | 1 | 1 | 6µs | 37µs | Contextual::Return::Value::BEGIN@1526 |
| 1 | 1 | 1 | 5µs | 14µs | Contextual::Return::BEGIN@1000 |
| 1 | 1 | 1 | 5µs | 19µs | Contextual::Return::BEGIN@493 |
| 1 | 1 | 1 | 5µs | 20µs | Contextual::Return::Value::BEGIN@1076 |
| 1 | 1 | 1 | 5µs | 14µs | Contextual::Return::Value::BEGIN@1130 |
| 1 | 1 | 1 | 5µs | 15µs | Contextual::Return::Value::BEGIN@1476 |
| 1 | 1 | 1 | 5µs | 14µs | Contextual::Return::Lvalue::BEGIN@1705 |
| 1 | 1 | 1 | 5µs | 15µs | Contextual::Return::Value::BEGIN@1575 |
| 1 | 1 | 1 | 5µs | 9µs | Contextual::Return::BEGIN@145 |
| 1 | 1 | 1 | 5µs | 19µs | Contextual::Return::BEGIN@370 |
| 1 | 1 | 1 | 5µs | 23µs | Contextual::Return::BEGIN@65 |
| 1 | 1 | 1 | 5µs | 14µs | Contextual::Return::Value::BEGIN@1290 |
| 1 | 1 | 1 | 4µs | 14µs | Contextual::Return::Value::BEGIN@1232 |
| 1 | 1 | 1 | 4µs | 14µs | Contextual::Return::Value::BEGIN@1376 |
| 1 | 1 | 1 | 4µs | 12µs | Contextual::Return::BEGIN@87 |
| 1 | 1 | 1 | 4µs | 14µs | Contextual::Return::Value::BEGIN@1176 |
| 1 | 1 | 1 | 4µs | 18µs | Contextual::Return::BEGIN@269 |
| 1 | 1 | 1 | 4µs | 8µs | Contextual::Return::BEGIN@313 |
| 1 | 1 | 1 | 4µs | 17µs | Contextual::Return::BEGIN@583 |
| 1 | 1 | 1 | 4µs | 7µs | Contextual::Return::BEGIN@354 |
| 1 | 1 | 1 | 4µs | 16µs | Contextual::Return::BEGIN@711 |
| 1 | 1 | 1 | 4µs | 13µs | Contextual::Return::BEGIN@290 |
| 1 | 1 | 1 | 4µs | 12µs | Contextual::Return::Lvalue::BEGIN@1717 |
| 1 | 1 | 1 | 4µs | 12µs | Contextual::Return::BEGIN@341 |
| 1 | 1 | 1 | 4µs | 14µs | Contextual::Return::BEGIN@499 |
| 1 | 1 | 1 | 4µs | 14µs | Contextual::Return::BEGIN@80 |
| 1 | 1 | 1 | 4µs | 4µs | Contextual::Return::Value::BEGIN@1075 |
| 1 | 1 | 1 | 4µs | 14µs | Contextual::Return::Value::BEGIN@1531 |
| 1 | 1 | 1 | 4µs | 13µs | Contextual::Return::Value::BEGIN@1083 |
| 1 | 1 | 1 | 3µs | 14µs | Contextual::Return::BEGIN@13 |
| 1 | 1 | 1 | 3µs | 13µs | Contextual::Return::BEGIN@845 |
| 1 | 1 | 1 | 2µs | 2µs | Contextual::Return::BEGIN@839 |
| 1 | 1 | 1 | 2µs | 2µs | Contextual::Return::BEGIN@705 |
| 1 | 1 | 1 | 2µs | 2µs | Contextual::Return::CORE:qr (opcode) |
| 1 | 1 | 1 | 400ns | 400ns | Contextual::Return::Value::CORE:qr (opcode) |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::DUMP |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::FREEZE |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::LIST |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Lvalue::DESTROY |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Lvalue::FETCH |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Lvalue::STORE |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Lvalue::TIESCALAR |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::RESULT |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::RETOBJ |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::VOID |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::AUTOLOAD |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::DESTROY |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1114] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1125] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1160] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1171] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1196] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1217] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1228] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1267] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1286] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1325] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1356] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1372] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1411] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1422] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1461] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1472] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1511] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1522] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::__ANON__[:1658] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::can |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::Value::isa |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::__ANON__[:1008] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::__ANON__[:1025] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::__ANON__[:114] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::__ANON__[:349] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::__ANON__[:462] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::__ANON__[:63] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::__ANON__[:72] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::__ANON__[:77] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::__ANON__[:799] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::__ANON__[:945] |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::_flag_self_ref_in |
| 0 | 0 | 0 | 0s | 0s | Contextual::Return::_in_context |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package Contextual::Return; | ||||
| 2 | 2 | 13µs | 2 | 32µs | # spent 19µs (6+13) within Contextual::Return::BEGIN@2 which was called:
# once (6µs+13µs) by IO::Prompter::BEGIN@9 at line 2 # spent 19µs making 1 call to Contextual::Return::BEGIN@2
# spent 13µs making 1 call to warnings::import |
| 3 | 2 | 33µs | 2 | 8µs | # spent 7µs (6+800ns) within Contextual::Return::BEGIN@3 which was called:
# once (6µs+800ns) by IO::Prompter::BEGIN@9 at line 3 # spent 7µs making 1 call to Contextual::Return::BEGIN@3
# spent 800ns making 1 call to strict::import |
| 4 | 1 | 300ns | our $VERSION = '0.004014'; | ||
| 5 | |||||
| 6 | 1 | 200ns | my %attrs_of; | ||
| 7 | |||||
| 8 | # This is localized as caller to hide the interim blocks... | ||||
| 9 | my $smart_caller; | ||||
| 10 | |||||
| 11 | # Fake out Carp::*, and Scalar::Util::blessed() very early... | ||||
| 12 | # spent 14µs within Contextual::Return::BEGIN@12 which was called:
# once (14µs+0s) by IO::Prompter::BEGIN@9 at line 115 | ||||
| 13 | 2 | 193µs | 2 | 26µs | # spent 14µs (3+11) within Contextual::Return::BEGIN@13 which was called:
# once (3µs+11µs) by IO::Prompter::BEGIN@9 at line 13 # spent 14µs making 1 call to Contextual::Return::BEGIN@13
# spent 11µs making 1 call to warnings::unimport |
| 14 | |||||
| 15 | 1 | 500ns | my $fallback_caller = *CORE::GLOBAL::caller{CODE}; | ||
| 16 | 1 | 400ns | if (!defined $fallback_caller) { | ||
| 17 | # spent 200µs within Contextual::Return::__ANON__[/home/hejohns/perl5/lib/perl5/Contextual/Return.pm:30] which was called 61 times, avg 3µs/call:
# 29 times (45µs+0s) by Pod::Simple::_accessorize at line 1528 of Pod/Simple.pm, avg 2µs/call
# 10 times (45µs+0s) by Data::Printer::Filter::import at line 8 of Data/Printer/Filter.pm, avg 4µs/call
# 5 times (29µs+0s) by ExtUtils::MakeMaker::Config::import at line 15 of ExtUtils/MakeMaker/Config.pm, avg 6µs/call
# 3 times (14µs+0s) by Locale::Maketext::Simple::import at line 114 of Locale/Maketext/Simple.pm, avg 5µs/call
# 3 times (12µs+0s) by version::import at line 49 of version.pm, avg 4µs/call
# 3 times (8µs+0s) by Locale::Maketext::Simple::import at line 123 of Locale/Maketext/Simple.pm, avg 3µs/call
# 3 times (5µs+0s) by Locale::Maketext::Simple::import at line 124 of Locale/Maketext/Simple.pm, avg 2µs/call
# once (13µs+0s) by Getopt::Long::GetOptionsFromArray at line 292 of Getopt/Long.pm
# once (11µs+0s) by Data::Printer::import at line 31 of Data/Printer.pm
# once (8µs+0s) by IO::Prompter::import at line 119 of IO/Prompter.pm
# once (6µs+0s) by FileHandle::import at line 71 of FileHandle.pm
# once (6µs+0s) by Module::Load::_who at line 129 of Module/Load.pm | ||||
| 18 | 61 | 12µs | my ($height) = @_; | ||
| 19 | 61 | 9µs | $height++; | ||
| 20 | 61 | 90µs | my @caller = CORE::caller($height); | ||
| 21 | 61 | 15µs | if ( CORE::caller() eq 'DB' ) { | ||
| 22 | # Oops, redo picking up @DB::args | ||||
| 23 | package DB; | ||||
| 24 | |||||
| - - | |||||
| 27 | 61 | 7µs | return if ! @caller; # empty | ||
| 28 | 61 | 96µs | return $caller[0] if ! wantarray; # scalar context | ||
| 29 | 2 | 8µs | return @_ ? @caller : @caller[0..2]; # extra info or regular | ||
| 30 | 1 | 2µs | }; | ||
| 31 | } | ||||
| 32 | $smart_caller = sub (;$) { | ||||
| 33 | my ($uplevels) = $_[0] || 0; | ||||
| 34 | my @caller; | ||||
| 35 | if (CORE::caller eq 'DB') { | ||||
| 36 | package DB; | ||||
| 37 | |||||
| - - | |||||
| 48 | else { | ||||
| 49 | if ($fallback_caller) { | ||||
| 50 | @caller = $fallback_caller->($uplevels + 5 + $Contextual::Return::uplevel) | ||||
| 51 | if $Contextual::Return::uplevel; | ||||
| 52 | @caller = $fallback_caller->($uplevels + 4); | ||||
| 53 | } | ||||
| 54 | else { | ||||
| 55 | @caller = CORE::caller($uplevels + 5 + $Contextual::Return::uplevel) | ||||
| 56 | if $Contextual::Return::uplevel; | ||||
| 57 | @caller = CORE::caller($uplevels + 4); | ||||
| 58 | } | ||||
| 59 | } | ||||
| 60 | return if ! @caller; # empty | ||||
| 61 | return $caller[0] if ! wantarray; # scalar context | ||||
| 62 | return @_ ? @caller : @caller[0..2]; # extra info or regular | ||||
| 63 | 1 | 1µs | }; | ||
| 64 | |||||
| 65 | 2 | 79µs | 2 | 42µs | # spent 23µs (5+19) within Contextual::Return::BEGIN@65 which was called:
# once (5µs+19µs) by IO::Prompter::BEGIN@9 at line 65 # spent 23µs making 1 call to Contextual::Return::BEGIN@65
# spent 19µs making 1 call to Exporter::import |
| 66 | 1 | 200ns | my $real_carp = *Carp::carp{CODE}; | ||
| 67 | 1 | 100ns | my $real_croak = *Carp::croak{CODE}; | ||
| 68 | |||||
| 69 | *Carp::carp = sub { | ||||
| 70 | goto &{$real_carp} if !$Contextual::Return::uplevel; | ||||
| 71 | warn _in_context(@_); | ||||
| 72 | 1 | 4µs | }; | ||
| 73 | |||||
| 74 | *Carp::croak = sub { | ||||
| 75 | goto &{$real_croak} if !$Contextual::Return::uplevel; | ||||
| 76 | die _in_context(@_); | ||||
| 77 | 1 | 800ns | }; | ||
| 78 | |||||
| 79 | # Scalar::Util::blessed()... | ||||
| 80 | 2 | 24µs | 2 | 24µs | # spent 14µs (4+10) within Contextual::Return::BEGIN@80 which was called:
# once (4µs+10µs) by IO::Prompter::BEGIN@9 at line 80 # spent 14µs making 1 call to Contextual::Return::BEGIN@80
# spent 10µs making 1 call to Exporter::import |
| 81 | |||||
| 82 | # Remember the current blessed()... | ||||
| 83 | 1 | 200ns | my $original_blessing = *Scalar::Util::blessed{CODE}; | ||
| 84 | |||||
| 85 | # ...and replace it... | ||||
| 86 | *Scalar::Util::blessed = sub($) { | ||||
| 87 | 2 | 108µs | 2 | 20µs | # spent 12µs (4+8) within Contextual::Return::BEGIN@87 which was called:
# once (4µs+8µs) by IO::Prompter::BEGIN@9 at line 87 # spent 12µs making 1 call to Contextual::Return::BEGIN@87
# spent 8µs making 1 call to warnings::unimport |
| 88 | |||||
| 89 | # Are we operating on a CRV??? | ||||
| 90 | my $attrs = $attrs_of{refaddr $_[0] or q{}}; | ||||
| 91 | |||||
| 92 | # If not, use the original code... | ||||
| 93 | goto &{$original_blessing} if !$attrs; | ||||
| 94 | |||||
| 95 | # Does this object have a BLESSED handler??? | ||||
| 96 | if (exists $attrs->{BLESSED}) { | ||||
| 97 | return $attrs->{BLESSED}->(@{$attrs->{args}}); | ||||
| 98 | } | ||||
| 99 | |||||
| 100 | # Otherwise, find the appropriate scalar handler... | ||||
| 101 | handler: | ||||
| 102 | for my $context (qw( OBJREF LAZY REF SCALAR VALUE NONVOID DEFAULT )) { | ||||
| 103 | my $handler = $attrs->{$context} | ||||
| 104 | or next handler; | ||||
| 105 | |||||
| 106 | my $obj_ref = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 107 | |||||
| 108 | my $was_blessed = $original_blessing->($obj_ref); | ||||
| 109 | return $was_blessed if $was_blessed; | ||||
| 110 | } | ||||
| 111 | |||||
| 112 | # Otherwise, simulate unblessed status... | ||||
| 113 | return undef; | ||||
| 114 | 1 | 5µs | }; | ||
| 115 | 1 | 78µs | 1 | 14µs | } # spent 14µs making 1 call to Contextual::Return::BEGIN@12 |
| 116 | |||||
| - - | |||||
| 119 | sub _in_context { | ||||
| 120 | my $msg = join q{}, @_; | ||||
| 121 | |||||
| 122 | # Start looking in caller... | ||||
| 123 | my $stack_frame = 1; | ||||
| 124 | my ($package, $file, $line, $sub) = CORE::caller($stack_frame++); | ||||
| 125 | |||||
| 126 | my ($orig_package, $prev_package) = ($package) x 2; | ||||
| 127 | my $LOC = qq{at $file line $line}; | ||||
| 128 | |||||
| 129 | # Walk up stack... | ||||
| 130 | STACK_FRAME: | ||||
| 131 | while (1) { | ||||
| 132 | my ($package, $file, $line, $sub) = CORE::caller($stack_frame++); | ||||
| 133 | |||||
| 134 | # Fall off the top of the stack... | ||||
| 135 | last STACK_FRAME if !defined $package; | ||||
| 136 | |||||
| 137 | # Ignore this module (and any helpers)... | ||||
| 138 | next STACK_FRAME if $package =~ m{^Contextual::Return}xms; | ||||
| 139 | |||||
| 140 | # Track the call up the stack... | ||||
| 141 | $LOC = qq{at $file line $line}; | ||||
| 142 | |||||
| 143 | # Ignore any @CARP_NOT'ed packages | ||||
| 144 | next STACK_FRAME | ||||
| 145 | 2 | 218µs | 2 | 14µs | # spent 9µs (5+5) within Contextual::Return::BEGIN@145 which was called:
# once (5µs+5µs) by IO::Prompter::BEGIN@9 at line 145 # spent 9µs making 1 call to Contextual::Return::BEGIN@145
# spent 5µs making 1 call to strict::unimport |
| 146 | |||||
| 147 | # Ignore transitions within original caller... | ||||
| 148 | next STACK_FRAME | ||||
| 149 | if $package eq $orig_package && $prev_package eq $orig_package; | ||||
| 150 | |||||
| 151 | # If we get a transition out of the original package, we're there... | ||||
| 152 | last STACK_FRAME; | ||||
| 153 | } | ||||
| 154 | |||||
| 155 | # Insert location details... | ||||
| 156 | $msg =~ s/<LOC>/$LOC/g or $msg =~ s/[^\S\n]*$/ $LOC/; | ||||
| 157 | $msg =~ s/$/\n/; | ||||
| 158 | return $msg; | ||||
| 159 | } | ||||
| 160 | |||||
| 161 | # Indentation corresponds to inherited fall-back relationships... | ||||
| 162 | 1 | 1µs | my @CONTEXTS = qw( | ||
| 163 | DEFAULT | ||||
| 164 | VOID | ||||
| 165 | NONVOID | ||||
| 166 | LIST | ||||
| 167 | SCALAR | ||||
| 168 | VALUE | ||||
| 169 | STR | ||||
| 170 | NUM | ||||
| 171 | BOOL | ||||
| 172 | PUREBOOL | ||||
| 173 | REF | ||||
| 174 | SCALARREF | ||||
| 175 | ARRAYREF | ||||
| 176 | CODEREF | ||||
| 177 | HASHREF | ||||
| 178 | GLOBREF | ||||
| 179 | OBJREF | ||||
| 180 | METHOD | ||||
| 181 | BLESSED | ||||
| 182 | ); | ||||
| 183 | |||||
| 184 | 1 | 2µs | my @ALL_EXPORTS = ( | ||
| 185 | @CONTEXTS, | ||||
| 186 | qw( | ||||
| 187 | LAZY RESULT RVALUE METHOD FAIL | ||||
| 188 | FIXED RECOVER LVALUE RETOBJ FAIL_WITH | ||||
| 189 | ACTIVE CLEANUP NVALUE STRICT BLESSED | ||||
| 190 | ) | ||||
| 191 | ); | ||||
| 192 | |||||
| 193 | 1 | 15µs | my %STD_NAME_FOR = map { $_ => $_ } @ALL_EXPORTS; | ||
| 194 | |||||
| 195 | # spent 566µs (518+48) within Contextual::Return::import which was called 2 times, avg 283µs/call:
# once (474µs+92µs) by IO::Prompter::BEGIN@9 at line 9 of IO/Prompter.pm
# once (44µs+-44µs) by Contextual::Return::Failure::BEGIN@4 at line 4 of Contextual/Return/Failure.pm | ||||
| 196 | # Load utility module for failure handlers... | ||||
| 197 | 2 | 62µs | if (require Contextual::Return::Failure) { | ||
| 198 | 2 | 2µs | *FAIL = \&Contextual::Return::Failure::_FAIL; | ||
| 199 | 2 | 600ns | *FAIL_WITH = \&Contextual::Return::Failure::_FAIL_WITH; | ||
| 200 | } | ||||
| 201 | |||||
| 202 | # Don't need the package name... | ||||
| 203 | 2 | 700ns | shift @_; | ||
| 204 | |||||
| 205 | # If args, export nothing by default; otherwise export all... | ||||
| 206 | 2 | 7µs | my %exports = @_ ? () : %STD_NAME_FOR; | ||
| 207 | |||||
| 208 | # All args are export either selectors and/or renamers... | ||||
| 209 | 2 | 3µs | while (my $selector = shift @_) { | ||
| 210 | 7 | 1µs | my $next_arg = $_[0]; | ||
| 211 | my $renamer = (defined $next_arg | ||||
| 212 | && !ref $next_arg | ||||
| 213 | 7 | 2µs | && !exists $STD_NAME_FOR{$next_arg}) | ||
| 214 | ? shift(@_) | ||||
| 215 | : undef; | ||||
| 216 | 7 | 11µs | 7 | 10µs | %exports = (%exports, _add_exports_for($selector, $renamer)); # spent 10µs making 7 calls to Contextual::Return::_add_exports_for, avg 1µs/call |
| 217 | } | ||||
| 218 | |||||
| 219 | # Loop through possible exports, exporting anything requested... | ||||
| 220 | 2 | 1µs | my $caller = CORE::caller; | ||
| 221 | EXPORT: | ||||
| 222 | 2 | 9µs | for my $subname (keys %exports) { | ||
| 223 | 2 | 119µs | 2 | 13µs | # spent 9µs (6+4) within Contextual::Return::BEGIN@223 which was called:
# once (6µs+4µs) by IO::Prompter::BEGIN@9 at line 223 # spent 9µs making 1 call to Contextual::Return::BEGIN@223
# spent 4µs making 1 call to strict::unimport |
| 224 | 39 | 37µs | *{$caller.'::'.$exports{$subname}} = \&{$subname}; | ||
| 225 | } | ||||
| 226 | }; | ||||
| 227 | |||||
| 228 | # spent 10µs within Contextual::Return::_add_exports_for which was called 7 times, avg 1µs/call:
# 7 times (10µs+0s) by Contextual::Return::import at line 216, avg 1µs/call | ||||
| 229 | 7 | 1µs | my ($selector, $renamer) = @_; | ||
| 230 | |||||
| 231 | # If no renamer, use original name... | ||||
| 232 | 7 | 900ns | $renamer ||= '%s'; | ||
| 233 | |||||
| 234 | # Handle different types of selector... | ||||
| 235 | 7 | 800ns | my $selector_type = ref($selector) || 'literal'; | ||
| 236 | |||||
| 237 | # Array selector recursively export each element... | ||||
| 238 | 7 | 1µs | if ($selector_type eq 'ARRAY') { | ||
| 239 | return map { _add_exports_for($_,$renamer) } @{$selector}; | ||||
| 240 | } | ||||
| 241 | elsif ($selector_type eq 'Regexp') { | ||||
| 242 | my @selected = grep {/$selector/} @ALL_EXPORTS; | ||||
| 243 | if (!@selected) { | ||||
| 244 | Carp::carp("use Contextual::Return $selector didn't export anything"); | ||||
| 245 | } | ||||
| 246 | 2 | 48µs | 2 | 27µs | # spent 26µs (8+18) within Contextual::Return::BEGIN@246 which was called:
# once (8µs+18µs) by IO::Prompter::BEGIN@9 at line 246 # spent 26µs making 1 call to Contextual::Return::BEGIN@246
# spent 1µs making 1 call to if::unimport |
| 247 | return map { $_ => sprintf($renamer, $_) } @selected; | ||||
| 248 | } | ||||
| 249 | elsif ($selector_type eq 'literal') { | ||||
| 250 | Carp::croak "Can't export $selector: no such handler" | ||||
| 251 | 7 | 1µs | if !exists $STD_NAME_FOR{$selector}; | ||
| 252 | 2 | 73µs | 2 | 294µs | # spent 293µs (275+19) within Contextual::Return::BEGIN@252 which was called:
# once (275µs+19µs) by IO::Prompter::BEGIN@9 at line 252 # spent 293µs making 1 call to Contextual::Return::BEGIN@252
# spent 1µs making 1 call to if::unimport |
| 253 | 7 | 9µs | return ( $selector => sprintf($renamer, $selector) ); | ||
| 254 | } | ||||
| 255 | else { | ||||
| 256 | Carp::croak "Can't use $selector_type as export specifier"; | ||||
| 257 | } | ||||
| 258 | } | ||||
| 259 | |||||
| 260 | |||||
| 261 | # Let handlers access the result object they're inside... | ||||
| 262 | |||||
| 263 | sub RETOBJ() { | ||||
| 264 | our $__RETOBJ__; | ||||
| 265 | return $__RETOBJ__; | ||||
| 266 | } | ||||
| 267 | |||||
| 268 | |||||
| 269 | 2 | 75µs | 2 | 32µs | # spent 18µs (4+14) within Contextual::Return::BEGIN@269 which was called:
# once (4µs+14µs) by IO::Prompter::BEGIN@9 at line 269 # spent 18µs making 1 call to Contextual::Return::BEGIN@269
# spent 14µs making 1 call to Exporter::import |
| 270 | |||||
| 271 | # Override return value in a C::R handler... | ||||
| 272 | sub RESULT(;&) { | ||||
| 273 | my ($block) = @_; | ||||
| 274 | |||||
| 275 | # Determine call context and arg list... | ||||
| 276 | my $context; | ||||
| 277 | my $args = do { package DB; $context=(CORE::caller 1)[5]; my $args = \@DB::args; ()=CORE::caller(1); $args }; | ||||
| 278 | |||||
| 279 | # No args -> return appropriate value... | ||||
| 280 | if (!@_) { | ||||
| 281 | return $context ? @{ $Contextual::Return::__RESULT__ || [] } | ||||
| 282 | : $Contextual::Return::__RESULT__->[0] | ||||
| 283 | ; | ||||
| 284 | } | ||||
| 285 | |||||
| 286 | # Hide from caller() and the enclosing eval{}... | ||||
| 287 | |||||
| 288 | # Evaluate block in context and cache result... | ||||
| 289 | local $Contextual::Return::uplevel = $Contextual::Return::uplevel+1; | ||||
| 290 | 2 | 80µs | 2 | 22µs | # spent 13µs (4+9) within Contextual::Return::BEGIN@290 which was called:
# once (4µs+9µs) by IO::Prompter::BEGIN@9 at line 290 # spent 13µs making 1 call to Contextual::Return::BEGIN@290
# spent 9µs making 1 call to warnings::unimport |
| 291 | $Contextual::Return::__RESULT__ | ||||
| 292 | = $context ? [ $block->(@{$args}) ] | ||||
| 293 | : defined $context ? [ scalar $block->(@{$args}) ] | ||||
| 294 | : do { $block->(@{$args}); [] } | ||||
| 295 | ; | ||||
| 296 | |||||
| 297 | return; | ||||
| 298 | } | ||||
| 299 | |||||
| 300 | sub RVALUE(&;@) :lvalue; | ||||
| 301 | sub LVALUE(&;@) :lvalue; | ||||
| 302 | sub NVALUE(&;@) :lvalue; | ||||
| 303 | |||||
| 304 | 1 | 800ns | my %opposite_of = ( | ||
| 305 | 'RVALUE' => 'LVALUE or NVALUE', | ||||
| 306 | 'LVALUE' => 'RVALUE or NVALUE', | ||||
| 307 | 'NVALUE' => 'LVALUE or RVALUE', | ||||
| 308 | ); | ||||
| 309 | |||||
| 310 | |||||
| 311 | # spent 12µs within Contextual::Return::BEGIN@311 which was called:
# once (12µs+0s) by IO::Prompter::BEGIN@9 at line 351 | ||||
| 312 | 1 | 2µs | for my $subname (qw( RVALUE LVALUE NVALUE) ) { | ||
| 313 | 2 | 121µs | 2 | 13µs | # spent 8µs (4+4) within Contextual::Return::BEGIN@313 which was called:
# once (4µs+4µs) by IO::Prompter::BEGIN@9 at line 313 # spent 8µs making 1 call to Contextual::Return::BEGIN@313
# spent 4µs making 1 call to strict::unimport |
| 314 | *{$subname} = sub(&;@) :lvalue { # (handler, return_lvalue); | ||||
| 315 | my $handler = shift; | ||||
| 316 | my $impl; | ||||
| 317 | my $args = do{ package DB; ()=CORE::caller(1); my $args = \@DB::args; ()=CORE::caller(1); $args }; | ||||
| 318 | if (@_==0) { | ||||
| 319 | $impl = tie $_[0], 'Contextual::Return::Lvalue', | ||||
| 320 | $subname => $handler, args=>$args; | ||||
| 321 | } | ||||
| 322 | elsif (@_==1 and $impl = tied $_[0]) { | ||||
| 323 | die _in_context "Can't install two $subname handlers" | ||||
| 324 | if exists $impl->{$subname}; | ||||
| 325 | $impl->{$subname} = $handler; | ||||
| 326 | } | ||||
| 327 | else { | ||||
| 328 | my $vals = join q{, }, map { tied $_ ? keys %{tied $_} | ||||
| 329 | : defined $_ ? $_ | ||||
| 330 | : 'undef' | ||||
| 331 | } @_; | ||||
| 332 | die _in_context "Expected a $opposite_of{$subname} block ", | ||||
| 333 | "after the $subname block <LOC> ", | ||||
| 334 | "but found instead: $vals\n"; | ||||
| 335 | } | ||||
| 336 | |||||
| 337 | # Handle void context calls... | ||||
| 338 | if (!defined wantarray && $impl->{NVALUE}) { | ||||
| 339 | # Fake out caller() and Carp... | ||||
| 340 | local $Contextual::Return::uplevel = 1; | ||||
| 341 | 2 | 69µs | 2 | 21µs | # spent 12µs (4+9) within Contextual::Return::BEGIN@341 which was called:
# once (4µs+9µs) by IO::Prompter::BEGIN@9 at line 341 # spent 12µs making 1 call to Contextual::Return::BEGIN@341
# spent 9µs making 1 call to warnings::unimport |
| 342 | |||||
| 343 | # Call and clear handler... | ||||
| 344 | local $Contextual::Return::__RETOBJ__ = $impl; | ||||
| 345 | $impl->{NVALUE}( @{$impl->{args}} ); | ||||
| 346 | delete $impl->{NVALUE}; | ||||
| 347 | } | ||||
| 348 | $_[0]; | ||||
| 349 | } | ||||
| 350 | 3 | 10µs | } | ||
| 351 | 1 | 18µs | 1 | 12µs | } # spent 12µs making 1 call to Contextual::Return::BEGIN@311 |
| 352 | |||||
| 353 | 1 | 300ns | for my $modifier_name (qw< STRICT FIXED ACTIVE >) { | ||
| 354 | 2 | 41µs | 2 | 10µs | # spent 7µs (4+3) within Contextual::Return::BEGIN@354 which was called:
# once (4µs+3µs) by IO::Prompter::BEGIN@9 at line 354 # spent 7µs making 1 call to Contextual::Return::BEGIN@354
# spent 3µs making 1 call to strict::unimport |
| 355 | *{$modifier_name} = sub ($) { | ||||
| 356 | my ($crv) = @_; | ||||
| 357 | my $attrs = $attrs_of{refaddr $crv or q{}}; | ||||
| 358 | |||||
| 359 | # Track context... | ||||
| 360 | my $wantarray = wantarray; | ||||
| 361 | 2 | 103µs | 2 | 2.23ms | # spent 2.21ms (1.88+331µs) within Contextual::Return::BEGIN@361 which was called:
# once (1.88ms+331µs) by IO::Prompter::BEGIN@9 at line 361 # spent 2.21ms making 1 call to Contextual::Return::BEGIN@361
# spent 18µs making 1 call to Exporter::import |
| 362 | $attrs->{want_pure_bool} ||= Want::want('BOOL'); | ||||
| 363 | |||||
| 364 | # Remember the modification... | ||||
| 365 | $attrs->{$modifier_name} = 1; | ||||
| 366 | |||||
| 367 | # Prepare for exception handling... | ||||
| 368 | my $recover = $attrs->{RECOVER}; | ||||
| 369 | local $Contextual::Return::uplevel = 2; | ||||
| 370 | 2 | 386µs | 2 | 34µs | # spent 19µs (5+15) within Contextual::Return::BEGIN@370 which was called:
# once (5µs+15µs) by IO::Prompter::BEGIN@9 at line 370 # spent 19µs making 1 call to Contextual::Return::BEGIN@370
# spent 15µs making 1 call to warnings::unimport |
| 371 | |||||
| 372 | # Handle list context directly, if possible... | ||||
| 373 | if ($wantarray) { | ||||
| 374 | local $Contextual::Return::__RESULT__; | ||||
| 375 | # List or ancestral handlers... | ||||
| 376 | handler: | ||||
| 377 | for my $context (qw(LIST VALUE NONVOID DEFAULT)) { | ||||
| 378 | my $handler = $attrs->{$context} | ||||
| 379 | or $attrs->{STRICT} and last handler | ||||
| 380 | or next handler; | ||||
| 381 | |||||
| 382 | my @rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 383 | if ($recover) { | ||||
| 384 | if (!$Contextual::Return::__RESULT__) { | ||||
| 385 | $Contextual::Return::__RESULT__ = [@rv]; | ||||
| 386 | } | ||||
| 387 | () = $recover->(@{$attrs->{args}}); | ||||
| 388 | } | ||||
| 389 | elsif ($@) { | ||||
| 390 | die $@; | ||||
| 391 | } | ||||
| 392 | |||||
| 393 | return @rv if !$Contextual::Return::__RESULT__; | ||||
| 394 | return @{$Contextual::Return::__RESULT__}; | ||||
| 395 | } | ||||
| 396 | # Convert to list from arrayref handler... | ||||
| 397 | if (!$attrs->{STRICT} and my $handler = $attrs->{ARRAYREF}) { | ||||
| 398 | my $array_ref = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 399 | |||||
| 400 | if ($recover) { | ||||
| 401 | if (!$Contextual::Return::__RESULT__) { | ||||
| 402 | $Contextual::Return::__RESULT__ = [$array_ref]; | ||||
| 403 | } | ||||
| 404 | scalar $recover->(@{$attrs->{args}}); | ||||
| 405 | } | ||||
| 406 | elsif ($@) { | ||||
| 407 | die $@; | ||||
| 408 | } | ||||
| 409 | |||||
| 410 | # Array ref may be returned directly, or via RESULT{}... | ||||
| 411 | $array_ref = $Contextual::Return::__RESULT__->[0] | ||||
| 412 | if $Contextual::Return::__RESULT__; | ||||
| 413 | |||||
| 414 | return @{$array_ref} if (ref $array_ref||q{}) eq 'ARRAY'; | ||||
| 415 | } | ||||
| 416 | # Return scalar object as one-elem list, if possible... | ||||
| 417 | handler: | ||||
| 418 | for my $context (qw(BOOL STR NUM VALUE SCALAR LAZY)) { | ||||
| 419 | last handler if $attrs->{STRICT}; | ||||
| 420 | return $crv if exists $attrs->{$context}; | ||||
| 421 | } | ||||
| 422 | $@ = _in_context "Can't call $attrs->{sub} in a list context"; | ||||
| 423 | if ($recover) { | ||||
| 424 | () = $recover->(@{$attrs->{args}}); | ||||
| 425 | } | ||||
| 426 | else { | ||||
| 427 | die $@; | ||||
| 428 | } | ||||
| 429 | } | ||||
| 430 | |||||
| 431 | # Handle void context directly... | ||||
| 432 | if (!defined $wantarray) { | ||||
| 433 | handler: | ||||
| 434 | for my $context (qw< VOID DEFAULT >) { | ||||
| 435 | my $handler = $attrs->{$context} | ||||
| 436 | or $attrs->{STRICT} and last handler | ||||
| 437 | or next handler; | ||||
| 438 | |||||
| 439 | eval { $attrs->{$context}->(@{$attrs->{args}}) }; | ||||
| 440 | if ($recover) { | ||||
| 441 | $recover->(@{$attrs->{args}}); | ||||
| 442 | } | ||||
| 443 | elsif ($@) { | ||||
| 444 | die $@; | ||||
| 445 | } | ||||
| 446 | last handler; | ||||
| 447 | } | ||||
| 448 | if ($attrs->{STRICT}) { | ||||
| 449 | $@ = _in_context "Can't call $attrs->{sub} in a void context"; | ||||
| 450 | if ($recover) { | ||||
| 451 | () = $recover->(@{$attrs->{args}}); | ||||
| 452 | } | ||||
| 453 | else { | ||||
| 454 | die $@; | ||||
| 455 | } | ||||
| 456 | } | ||||
| 457 | return; | ||||
| 458 | } | ||||
| 459 | |||||
| 460 | # Otherwise, let someone else handle it... | ||||
| 461 | return $crv; | ||||
| 462 | } | ||||
| 463 | 3 | 9µs | } | ||
| 464 | |||||
| 465 | sub LIST (;&$) { | ||||
| 466 | my ($block, $crv) = @_; | ||||
| 467 | |||||
| 468 | # Handle simple context tests... | ||||
| 469 | return !!(CORE::caller 1)[5] if !@_; | ||||
| 470 | |||||
| 471 | # Ensure we have an object... | ||||
| 472 | my $attrs; | ||||
| 473 | if (!refaddr $crv) { | ||||
| 474 | my $args = do{ package DB; ()=CORE::caller(1); my $args = \@DB::args; ()=CORE::caller(1); $args }; | ||||
| 475 | my $subname = (CORE::caller(1))[3]; | ||||
| 476 | if (!defined $subname) { | ||||
| 477 | $subname = 'bare LIST {...}'; | ||||
| 478 | } | ||||
| 479 | $crv = bless \my $scalar, 'Contextual::Return::Value'; | ||||
| 480 | $attrs = $attrs_of{refaddr $crv} = { args => $args, sub => $subname }; | ||||
| 481 | } | ||||
| 482 | else { | ||||
| 483 | $attrs = $attrs_of{refaddr $crv}; | ||||
| 484 | } | ||||
| 485 | local $Contextual::Return::__RETOBJ__ = $crv; | ||||
| 486 | |||||
| 487 | # Handle repetitions... | ||||
| 488 | die _in_context "Can't install two LIST handlers" | ||||
| 489 | if exists $attrs->{LIST}; | ||||
| 490 | |||||
| 491 | # Identify contexts... | ||||
| 492 | my $wantarray = wantarray; | ||||
| 493 | 2 | 30µs | 2 | 33µs | # spent 19µs (5+14) within Contextual::Return::BEGIN@493 which was called:
# once (5µs+14µs) by IO::Prompter::BEGIN@9 at line 493 # spent 19µs making 1 call to Contextual::Return::BEGIN@493
# spent 14µs making 1 call to Exporter::import |
| 494 | $attrs->{want_pure_bool} ||= Want::want('BOOL'); | ||||
| 495 | |||||
| 496 | # Prepare for exception handling... | ||||
| 497 | my $recover = $attrs->{RECOVER}; | ||||
| 498 | local $Contextual::Return::uplevel = 2; | ||||
| 499 | 2 | 276µs | 2 | 24µs | # spent 14µs (4+10) within Contextual::Return::BEGIN@499 which was called:
# once (4µs+10µs) by IO::Prompter::BEGIN@9 at line 499 # spent 14µs making 1 call to Contextual::Return::BEGIN@499
# spent 10µs making 1 call to warnings::unimport |
| 500 | |||||
| 501 | # Handle list context directly... | ||||
| 502 | if ($wantarray) { | ||||
| 503 | local $Contextual::Return::__RESULT__; | ||||
| 504 | |||||
| 505 | my @rv = eval { $block->(@{$attrs->{args}}) }; | ||||
| 506 | if ($recover) { | ||||
| 507 | if (!$Contextual::Return::__RESULT__) { | ||||
| 508 | $Contextual::Return::__RESULT__ = [@rv]; | ||||
| 509 | } | ||||
| 510 | () = $recover->(@{$attrs->{args}}); | ||||
| 511 | } | ||||
| 512 | elsif ($@) { | ||||
| 513 | die $@; | ||||
| 514 | } | ||||
| 515 | |||||
| 516 | return @rv if !$Contextual::Return::__RESULT__; | ||||
| 517 | return @{$Contextual::Return::__RESULT__}; | ||||
| 518 | } | ||||
| 519 | |||||
| 520 | # Handle void context directly... | ||||
| 521 | if (!defined $wantarray) { | ||||
| 522 | handler: | ||||
| 523 | for my $context (qw< VOID DEFAULT >) { | ||||
| 524 | my $handler = $attrs->{$context} | ||||
| 525 | or $attrs->{STRICT} and last handler | ||||
| 526 | or next handler; | ||||
| 527 | |||||
| 528 | eval { $attrs->{$context}->(@{$attrs->{args}}) }; | ||||
| 529 | if ($recover) { | ||||
| 530 | $recover->(@{$attrs->{args}}); | ||||
| 531 | } | ||||
| 532 | elsif ($@) { | ||||
| 533 | die $@; | ||||
| 534 | } | ||||
| 535 | last handler; | ||||
| 536 | } | ||||
| 537 | if ($attrs->{STRICT}) { | ||||
| 538 | $@ = _in_context "Can't call $attrs->{sub} in a void context"; | ||||
| 539 | if ($recover) { | ||||
| 540 | () = $recover->(@{$attrs->{args}}); | ||||
| 541 | } | ||||
| 542 | else { | ||||
| 543 | die $@; | ||||
| 544 | } | ||||
| 545 | } | ||||
| 546 | return; | ||||
| 547 | } | ||||
| 548 | |||||
| 549 | # Otherwise, cache handler... | ||||
| 550 | $attrs->{LIST} = $block; | ||||
| 551 | return $crv; | ||||
| 552 | } | ||||
| 553 | |||||
| 554 | |||||
| 555 | sub VOID (;&$) { | ||||
| 556 | my ($block, $crv) = @_; | ||||
| 557 | |||||
| 558 | # Handle simple context tests... | ||||
| 559 | return !defined( (CORE::caller 1)[5] ) if !@_; | ||||
| 560 | |||||
| 561 | # Ensure we have an object... | ||||
| 562 | my $attrs; | ||||
| 563 | if (!refaddr $crv) { | ||||
| 564 | my $args = do{ package DB; ()=CORE::caller(1); my $args = \@DB::args; ()=CORE::caller(1); $args }; | ||||
| 565 | my $subname = (CORE::caller(1))[3]; | ||||
| 566 | if (!defined $subname) { | ||||
| 567 | $subname = 'bare VOID {...}'; | ||||
| 568 | } | ||||
| 569 | $crv = bless \my $scalar, 'Contextual::Return::Value'; | ||||
| 570 | $attrs = $attrs_of{refaddr $crv} = { args => $args, sub => $subname }; | ||||
| 571 | } | ||||
| 572 | else { | ||||
| 573 | $attrs = $attrs_of{refaddr $crv}; | ||||
| 574 | } | ||||
| 575 | local $Contextual::Return::__RETOBJ__ = $crv; | ||||
| 576 | |||||
| 577 | # Handle repetitions... | ||||
| 578 | die _in_context "Can't install two VOID handlers" | ||||
| 579 | if exists $attrs->{VOID}; | ||||
| 580 | |||||
| 581 | # Identify contexts... | ||||
| 582 | my $wantarray = wantarray; | ||||
| 583 | 2 | 28µs | 2 | 30µs | # spent 17µs (4+13) within Contextual::Return::BEGIN@583 which was called:
# once (4µs+13µs) by IO::Prompter::BEGIN@9 at line 583 # spent 17µs making 1 call to Contextual::Return::BEGIN@583
# spent 13µs making 1 call to Exporter::import |
| 584 | $attrs->{want_pure_bool} ||= Want::want('BOOL'); | ||||
| 585 | |||||
| 586 | # Prepare for exception handling... | ||||
| 587 | my $recover = $attrs->{RECOVER}; | ||||
| 588 | local $Contextual::Return::uplevel = 2; | ||||
| 589 | 2 | 262µs | 2 | 25µs | # spent 16µs (7+9) within Contextual::Return::BEGIN@589 which was called:
# once (7µs+9µs) by IO::Prompter::BEGIN@9 at line 589 # spent 16µs making 1 call to Contextual::Return::BEGIN@589
# spent 9µs making 1 call to warnings::unimport |
| 590 | |||||
| 591 | # Handle list context directly, if possible... | ||||
| 592 | if ($wantarray) { | ||||
| 593 | local $Contextual::Return::__RESULT__; | ||||
| 594 | # List or ancestral handlers... | ||||
| 595 | handler: | ||||
| 596 | for my $context (qw(LIST VALUE NONVOID DEFAULT)) { | ||||
| 597 | my $handler = $attrs->{$context} | ||||
| 598 | or $attrs->{STRICT} and last handler | ||||
| 599 | or next handler; | ||||
| 600 | |||||
| 601 | my @rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 602 | if ($recover) { | ||||
| 603 | if (!$Contextual::Return::__RESULT__) { | ||||
| 604 | $Contextual::Return::__RESULT__ = [@rv]; | ||||
| 605 | } | ||||
| 606 | () = $recover->(@{$attrs->{args}}); | ||||
| 607 | } | ||||
| 608 | elsif ($@) { | ||||
| 609 | die $@; | ||||
| 610 | } | ||||
| 611 | |||||
| 612 | return @rv if !$Contextual::Return::__RESULT__; | ||||
| 613 | return @{$Contextual::Return::__RESULT__}; | ||||
| 614 | } | ||||
| 615 | # Convert to list from arrayref handler... | ||||
| 616 | if (!$attrs->{STRICT} and my $handler = $attrs->{ARRAYREF}) { | ||||
| 617 | my $array_ref = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 618 | |||||
| 619 | if ($recover) { | ||||
| 620 | if (!$Contextual::Return::__RESULT__) { | ||||
| 621 | $Contextual::Return::__RESULT__ = [$array_ref]; | ||||
| 622 | } | ||||
| 623 | scalar $recover->(@{$attrs->{args}}); | ||||
| 624 | } | ||||
| 625 | elsif ($@) { | ||||
| 626 | die $@; | ||||
| 627 | } | ||||
| 628 | |||||
| 629 | # Array ref may be returned directly, or via RESULT{}... | ||||
| 630 | $array_ref = $Contextual::Return::__RESULT__->[0] | ||||
| 631 | if $Contextual::Return::__RESULT__; | ||||
| 632 | |||||
| 633 | return @{$array_ref} if (ref $array_ref||q{}) eq 'ARRAY'; | ||||
| 634 | } | ||||
| 635 | # Return scalar object as one-elem list, if possible... | ||||
| 636 | handler: | ||||
| 637 | for my $context (qw(BOOL STR NUM VALUE SCALAR LAZY)) { | ||||
| 638 | last handler if $attrs->{STRICT}; | ||||
| 639 | return $crv if exists $attrs->{$context}; | ||||
| 640 | } | ||||
| 641 | $@ = _in_context "Can't call $attrs->{sub} in a list context"; | ||||
| 642 | if ($recover) { | ||||
| 643 | () = $recover->(@{$attrs->{args}}); | ||||
| 644 | } | ||||
| 645 | else { | ||||
| 646 | die $@; | ||||
| 647 | } | ||||
| 648 | } | ||||
| 649 | |||||
| 650 | # Handle void context directly... | ||||
| 651 | if (!defined $wantarray) { | ||||
| 652 | eval { $block->(@{$attrs->{args}}) }; | ||||
| 653 | |||||
| 654 | if ($recover) { | ||||
| 655 | $recover->(@{$attrs->{args}}); | ||||
| 656 | } | ||||
| 657 | elsif ($@) { | ||||
| 658 | die $@; | ||||
| 659 | } | ||||
| 660 | |||||
| 661 | return; | ||||
| 662 | } | ||||
| 663 | |||||
| 664 | # Otherwise, cache handler... | ||||
| 665 | $attrs->{VOID} = $block; | ||||
| 666 | return $crv; | ||||
| 667 | } | ||||
| 668 | |||||
| 669 | 1 | 200ns | for my $context (qw( SCALAR NONVOID )) { | ||
| 670 | 2 | 122µs | 2 | 15µs | # spent 10µs (6+5) within Contextual::Return::BEGIN@670 which was called:
# once (6µs+5µs) by IO::Prompter::BEGIN@9 at line 670 # spent 10µs making 1 call to Contextual::Return::BEGIN@670
# spent 5µs making 1 call to strict::unimport |
| 671 | *{$context} = sub (;&$) { | ||||
| 672 | my ($block, $crv) = @_; | ||||
| 673 | |||||
| 674 | # Handle simple context tests... | ||||
| 675 | if (!@_) { | ||||
| 676 | my $callers_context = (CORE::caller 1)[5]; | ||||
| 677 | return defined $callers_context | ||||
| 678 | && ($context eq 'NONVOID' || !$callers_context); | ||||
| 679 | } | ||||
| 680 | |||||
| 681 | # Ensure we have an object... | ||||
| 682 | my $attrs; | ||||
| 683 | if (!refaddr $crv) { | ||||
| 684 | my $args = do{ package DB; ()=CORE::caller(1); my $args = \@DB::args; ()=CORE::caller(1); $args }; | ||||
| 685 | my $subname = (CORE::caller(1))[3]; | ||||
| 686 | if (!defined $subname) { | ||||
| 687 | $subname = "bare $context {...}"; | ||||
| 688 | } | ||||
| 689 | $crv = bless \my $scalar, 'Contextual::Return::Value'; | ||||
| 690 | $attrs = $attrs_of{refaddr $crv} | ||||
| 691 | = { args => $args, sub => $subname }; | ||||
| 692 | } | ||||
| 693 | else { | ||||
| 694 | $attrs = $attrs_of{refaddr $crv}; | ||||
| 695 | } | ||||
| 696 | local $Contextual::Return::__RETOBJ__ = $crv; | ||||
| 697 | |||||
| 698 | # Make sure this block is a possibility too... | ||||
| 699 | die _in_context "Can't install two $context handlers" | ||||
| 700 | if exists $attrs->{$context}; | ||||
| 701 | $attrs->{$context} = $block; | ||||
| 702 | |||||
| 703 | # Identify contexts... | ||||
| 704 | my $wantarray = wantarray; | ||||
| 705 | 2 | 27µs | 1 | 2µs | # spent 2µs within Contextual::Return::BEGIN@705 which was called:
# once (2µs+0s) by IO::Prompter::BEGIN@9 at line 705 # spent 2µs making 1 call to Contextual::Return::BEGIN@705 |
| 706 | $attrs->{want_pure_bool} ||= Want::want('BOOL'); | ||||
| 707 | |||||
| 708 | # Prepare for exception handling... | ||||
| 709 | my $recover = $attrs->{RECOVER}; | ||||
| 710 | local $Contextual::Return::uplevel = 2; | ||||
| 711 | 2 | 321µs | 2 | 28µs | # spent 16µs (4+12) within Contextual::Return::BEGIN@711 which was called:
# once (4µs+12µs) by IO::Prompter::BEGIN@9 at line 711 # spent 16µs making 1 call to Contextual::Return::BEGIN@711
# spent 12µs making 1 call to warnings::unimport |
| 712 | |||||
| 713 | # Handle list context directly, if possible... | ||||
| 714 | if ($wantarray) { | ||||
| 715 | local $Contextual::Return::__RESULT__; | ||||
| 716 | |||||
| 717 | # List or ancestral handlers... | ||||
| 718 | handler: | ||||
| 719 | for my $context (qw(LIST VALUE NONVOID DEFAULT)) { | ||||
| 720 | my $handler = $attrs->{$context} | ||||
| 721 | or $attrs->{STRICT} and last handler | ||||
| 722 | or next handler; | ||||
| 723 | |||||
| 724 | my @rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 725 | if ($recover) { | ||||
| 726 | if (!$Contextual::Return::__RESULT__) { | ||||
| 727 | $Contextual::Return::__RESULT__ = [@rv]; | ||||
| 728 | } | ||||
| 729 | () = $recover->(@{$attrs->{args}}); | ||||
| 730 | } | ||||
| 731 | elsif ($@) { | ||||
| 732 | die $@; | ||||
| 733 | } | ||||
| 734 | |||||
| 735 | return @rv if !$Contextual::Return::__RESULT__; | ||||
| 736 | return @{$Contextual::Return::__RESULT__}; | ||||
| 737 | } | ||||
| 738 | # Convert to list from arrayref handler... | ||||
| 739 | if (!$attrs->{STRICT} and my $handler = $attrs->{ARRAYREF}) { | ||||
| 740 | |||||
| 741 | my $array_ref = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 742 | if ($recover) { | ||||
| 743 | if (!$Contextual::Return::__RESULT__) { | ||||
| 744 | $Contextual::Return::__RESULT__ = [$array_ref]; | ||||
| 745 | } | ||||
| 746 | scalar $recover->(@{$attrs->{args}}); | ||||
| 747 | } | ||||
| 748 | elsif ($@) { | ||||
| 749 | die $@; | ||||
| 750 | } | ||||
| 751 | |||||
| 752 | # Array ref may be returned directly, or via RESULT{}... | ||||
| 753 | $array_ref = $Contextual::Return::__RESULT__->[0] | ||||
| 754 | if $Contextual::Return::__RESULT__; | ||||
| 755 | |||||
| 756 | return @{$array_ref} if (ref $array_ref||q{}) eq 'ARRAY'; | ||||
| 757 | } | ||||
| 758 | # Return scalar object as one-elem list, if possible... | ||||
| 759 | handler: | ||||
| 760 | for my $context (qw(BOOL STR NUM VALUE SCALAR LAZY)) { | ||||
| 761 | last if $attrs->{STRICT}; | ||||
| 762 | return $crv if exists $attrs->{$context}; | ||||
| 763 | } | ||||
| 764 | die _in_context "Can't call $attrs->{sub} in a list context"; | ||||
| 765 | } | ||||
| 766 | |||||
| 767 | # Handle void context directly... | ||||
| 768 | if (!defined $wantarray) { | ||||
| 769 | handler: | ||||
| 770 | for my $context (qw< VOID DEFAULT >) { | ||||
| 771 | my $handler = $attrs->{$context} | ||||
| 772 | or $attrs->{STRICT} and last handler | ||||
| 773 | or next handler; | ||||
| 774 | |||||
| 775 | eval { $handler->(@{$attrs->{args}}) }; | ||||
| 776 | if ($recover) { | ||||
| 777 | $recover->(@{$attrs->{args}}); | ||||
| 778 | } | ||||
| 779 | elsif ($@) { | ||||
| 780 | die $@; | ||||
| 781 | } | ||||
| 782 | |||||
| 783 | last handler; | ||||
| 784 | } | ||||
| 785 | if ($attrs->{STRICT}) { | ||||
| 786 | $@ = _in_context "Can't call $attrs->{sub} in a void context"; | ||||
| 787 | if ($recover) { | ||||
| 788 | () = $recover->(@{$attrs->{args}}); | ||||
| 789 | } | ||||
| 790 | else { | ||||
| 791 | die $@; | ||||
| 792 | } | ||||
| 793 | } | ||||
| 794 | return; | ||||
| 795 | } | ||||
| 796 | |||||
| 797 | # Otherwise, defer evaluation by returning an object... | ||||
| 798 | return $crv; | ||||
| 799 | } | ||||
| 800 | 2 | 5µs | } | ||
| 801 | |||||
| 802 | handler: | ||||
| 803 | 1 | 500ns | for my $context_name (@CONTEXTS, qw< RECOVER _internal_LIST CLEANUP >) { | ||
| 804 | 22 | 5µs | next handler if $context_name eq 'LIST' # These | ||
| 805 | || $context_name eq 'VOID' # four | ||||
| 806 | || $context_name eq 'SCALAR' # handled | ||||
| 807 | || $context_name eq 'NONVOID'; # separately | ||||
| 808 | |||||
| 809 | 2 | 117µs | 2 | 14µs | # spent 10µs (6+4) within Contextual::Return::BEGIN@809 which was called:
# once (6µs+4µs) by IO::Prompter::BEGIN@9 at line 809 # spent 10µs making 1 call to Contextual::Return::BEGIN@809
# spent 4µs making 1 call to strict::unimport |
| 810 | *{$context_name} = sub (&;$) { | ||||
| 811 | my ($block, $crv) = @_; | ||||
| 812 | |||||
| 813 | # Ensure we have an object... | ||||
| 814 | my $attrs; | ||||
| 815 | if (!refaddr $crv) { | ||||
| 816 | my $args = do{ package DB; ()=CORE::caller(1); my $args = \@DB::args; ()=CORE::caller(1); $args }; | ||||
| 817 | my $subname = (CORE::caller(1))[3]; | ||||
| 818 | if (!defined $subname) { | ||||
| 819 | $subname = "bare $context_name {...}"; | ||||
| 820 | } | ||||
| 821 | $crv = bless \my $scalar, 'Contextual::Return::Value'; | ||||
| 822 | $attrs = $attrs_of{refaddr $crv} | ||||
| 823 | = { args => $args, sub => $subname }; | ||||
| 824 | } | ||||
| 825 | else { | ||||
| 826 | $attrs = $attrs_of{refaddr $crv}; | ||||
| 827 | } | ||||
| 828 | local $Contextual::Return::__RETOBJ__ = $crv; | ||||
| 829 | |||||
| 830 | # Make sure this block is a possibility too... | ||||
| 831 | if ($context_name ne '_internal_LIST') { | ||||
| 832 | die _in_context "Can't install two $context_name handlers" | ||||
| 833 | if exists $attrs->{$context_name}; | ||||
| 834 | $attrs->{$context_name} = $block; | ||||
| 835 | } | ||||
| 836 | |||||
| 837 | # Identify contexts... | ||||
| 838 | my $wantarray = wantarray; | ||||
| 839 | 2 | 27µs | 1 | 2µs | # spent 2µs within Contextual::Return::BEGIN@839 which was called:
# once (2µs+0s) by IO::Prompter::BEGIN@9 at line 839 # spent 2µs making 1 call to Contextual::Return::BEGIN@839 |
| 840 | $attrs->{want_pure_bool} ||= Want::want('BOOL'); | ||||
| 841 | |||||
| 842 | # Prepare for exception handling... | ||||
| 843 | my $recover = $attrs->{RECOVER}; | ||||
| 844 | local $Contextual::Return::uplevel = 2; | ||||
| 845 | 2 | 462µs | 2 | 22µs | # spent 13µs (3+9) within Contextual::Return::BEGIN@845 which was called:
# once (3µs+9µs) by IO::Prompter::BEGIN@9 at line 845 # spent 13µs making 1 call to Contextual::Return::BEGIN@845
# spent 9µs making 1 call to warnings::unimport |
| 846 | |||||
| 847 | # Handle list context directly, if possible... | ||||
| 848 | if ($wantarray) { | ||||
| 849 | local $Contextual::Return::__RESULT__ | ||||
| 850 | = $context_name eq 'RECOVER' ? $Contextual::Return::__RESULT__ | ||||
| 851 | : undef | ||||
| 852 | ; | ||||
| 853 | |||||
| 854 | # List or ancestral handlers... | ||||
| 855 | handler: | ||||
| 856 | for my $context (qw(LIST VALUE NONVOID DEFAULT)) { | ||||
| 857 | my $handler = $attrs->{$context} | ||||
| 858 | or $attrs->{STRICT} and last handler | ||||
| 859 | or next handler; | ||||
| 860 | |||||
| 861 | my @rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 862 | if ($recover) { | ||||
| 863 | if (!$Contextual::Return::__RESULT__) { | ||||
| 864 | $Contextual::Return::__RESULT__ = [@rv]; | ||||
| 865 | } | ||||
| 866 | () = $recover->(@{$attrs->{args}}); | ||||
| 867 | } | ||||
| 868 | elsif ($@) { | ||||
| 869 | die $@; | ||||
| 870 | } | ||||
| 871 | |||||
| 872 | return @rv if !$Contextual::Return::__RESULT__; | ||||
| 873 | return @{$Contextual::Return::__RESULT__}; | ||||
| 874 | } | ||||
| 875 | # Convert to list from arrayref handler... | ||||
| 876 | if (!$attrs->{STRICT} and my $handler = $attrs->{ARRAYREF}) { | ||||
| 877 | local $Contextual::Return::uplevel = 2; | ||||
| 878 | |||||
| 879 | # Array ref may be returned directly, or via RESULT{}... | ||||
| 880 | my $array_ref = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 881 | if ($recover) { | ||||
| 882 | if (!$Contextual::Return::__RESULT__) { | ||||
| 883 | $Contextual::Return::__RESULT__ = [$array_ref]; | ||||
| 884 | } | ||||
| 885 | scalar $recover->(@{$attrs->{args}}); | ||||
| 886 | } | ||||
| 887 | elsif ($@) { | ||||
| 888 | die $@; | ||||
| 889 | } | ||||
| 890 | |||||
| 891 | $array_ref = $Contextual::Return::__RESULT__->[0] | ||||
| 892 | if $Contextual::Return::__RESULT__; | ||||
| 893 | |||||
| 894 | return @{$array_ref} if (ref $array_ref||q{}) eq 'ARRAY'; | ||||
| 895 | } | ||||
| 896 | # Return scalar object as one-elem list, if possible... | ||||
| 897 | handler: | ||||
| 898 | for my $context (qw(BOOL STR NUM VALUE SCALAR LAZY)) { | ||||
| 899 | last if $attrs->{STRICT}; | ||||
| 900 | return $crv if exists $attrs->{$context}; | ||||
| 901 | } | ||||
| 902 | $@ = _in_context "Can't call $attrs->{sub} in a list context"; | ||||
| 903 | if ($recover) { | ||||
| 904 | () = $recover->(@{$attrs->{args}}); | ||||
| 905 | } | ||||
| 906 | else { | ||||
| 907 | die $@; | ||||
| 908 | } | ||||
| 909 | } | ||||
| 910 | |||||
| 911 | # Handle void context directly... | ||||
| 912 | if (!defined $wantarray) { | ||||
| 913 | handler: | ||||
| 914 | for my $context (qw(VOID DEFAULT)) { | ||||
| 915 | if (!$attrs->{$context}) { | ||||
| 916 | last handler if $attrs->{STRICT}; | ||||
| 917 | next handler; | ||||
| 918 | } | ||||
| 919 | |||||
| 920 | eval { $attrs->{$context}->(@{$attrs->{args}}) }; | ||||
| 921 | |||||
| 922 | if ($recover) { | ||||
| 923 | $recover->(@{$attrs->{args}}); | ||||
| 924 | } | ||||
| 925 | elsif ($@) { | ||||
| 926 | die $@; | ||||
| 927 | } | ||||
| 928 | |||||
| 929 | last handler; | ||||
| 930 | } | ||||
| 931 | if ($attrs->{STRICT}) { | ||||
| 932 | $@ = _in_context "Can't call $attrs->{sub} in a void context"; | ||||
| 933 | if ($recover) { | ||||
| 934 | () = $recover->(@{$attrs->{args}}); | ||||
| 935 | } | ||||
| 936 | else { | ||||
| 937 | die $@; | ||||
| 938 | } | ||||
| 939 | } | ||||
| 940 | return; | ||||
| 941 | } | ||||
| 942 | |||||
| 943 | # Otherwise, defer evaluation by returning an object... | ||||
| 944 | return $crv; | ||||
| 945 | } | ||||
| 946 | 18 | 87µs | } | ||
| 947 | |||||
| 948 | # Alias LAZY to SCALAR... | ||||
| 949 | 1 | 700ns | *LAZY = *SCALAR; | ||
| 950 | |||||
| 951 | |||||
| 952 | # Set $Data::Dumper::Freezer to 'Contextual::Return::FREEZE' to be able to | ||||
| 953 | # dump contextual return values... | ||||
| 954 | |||||
| 955 | 1 | 100ns | my %operator_impl; | ||
| 956 | |||||
| 957 | 1 | 6µs | 1 | 2µs | my $no_handler_message = qr{ # spent 2µs making 1 call to Contextual::Return::CORE:qr |
| 958 | ^ Can't [ ] call [ ] .*? [ ] in [ ] [\w]+ [ ] context | ||||
| 959 | | ^ [\w:]+ [ ] can't [ ] return [ ] a [ ] \w+ [ ] reference | ||||
| 960 | }xms; | ||||
| 961 | |||||
| 962 | sub _flag_self_ref_in { | ||||
| 963 | my ($data_ref, $obj_ref) = @_; | ||||
| 964 | my $type = ref $data_ref; | ||||
| 965 | return if !$type; | ||||
| 966 | for my $ref ( $type eq 'SCALAR' ? ${$data_ref} : $type eq 'ARRAY' ? @{$data_ref} : ()) { | ||||
| 967 | 2 | 100µs | 2 | 30µs | # spent 18µs (6+12) within Contextual::Return::BEGIN@967 which was called:
# once (6µs+12µs) by IO::Prompter::BEGIN@9 at line 967 # spent 18µs making 1 call to Contextual::Return::BEGIN@967
# spent 12µs making 1 call to warnings::unimport |
| 968 | if (refaddr($ref) == refaddr($obj_ref)) { | ||||
| 969 | $ref = '<<<self-reference>>>'; | ||||
| 970 | } | ||||
| 971 | } | ||||
| 972 | } | ||||
| 973 | |||||
| 974 | sub FREEZE { | ||||
| 975 | my ($self) = @_; | ||||
| 976 | my $attrs_ref = $attrs_of{refaddr $self}; | ||||
| 977 | my $args_ref = $attrs_ref->{args}; | ||||
| 978 | |||||
| 979 | my @no_handler; | ||||
| 980 | |||||
| 981 | # Call appropriate operator handler, defusing and recording exceptions... | ||||
| 982 | my $overloaded = sub { | ||||
| 983 | my ($context, $op) = @_; | ||||
| 984 | |||||
| 985 | # Try the operator... | ||||
| 986 | my $retval = eval { $operator_impl{$op}->($self,@{$args_ref}) }; | ||||
| 987 | |||||
| 988 | # Detect and report internal exceptions... | ||||
| 989 | if (my $exception = $@) { | ||||
| 990 | if ($exception =~ $no_handler_message) { | ||||
| 991 | push @no_handler, $context; | ||||
| 992 | return (); | ||||
| 993 | } | ||||
| 994 | chomp $exception; | ||||
| 995 | return { $context => "<<<Throws exception: $exception>>>" }; | ||||
| 996 | } | ||||
| 997 | |||||
| 998 | # Detect self-referential overloadings (to avoid infinite recursion)... | ||||
| 999 | { | ||||
| 1000 | 2 | 314µs | 2 | 23µs | # spent 14µs (5+9) within Contextual::Return::BEGIN@1000 which was called:
# once (5µs+9µs) by IO::Prompter::BEGIN@9 at line 1000 # spent 14µs making 1 call to Contextual::Return::BEGIN@1000
# spent 9µs making 1 call to warnings::unimport |
| 1001 | if (ref $retval eq 'REF' && eval{ ${$retval} == ${$self} }) { | ||||
| 1002 | return { $context => "<<<self-reference>>>" }; | ||||
| 1003 | } | ||||
| 1004 | } | ||||
| 1005 | |||||
| 1006 | # Normal return of contextual value labelled by context... | ||||
| 1007 | return { $context => $retval }; | ||||
| 1008 | }; | ||||
| 1009 | |||||
| 1010 | my @values; | ||||
| 1011 | |||||
| 1012 | # Where did this value originate? | ||||
| 1013 | push @values, { ISA => 'Contextual::Return::Value' }; | ||||
| 1014 | push @values, { FROM => $attrs_ref->{sub} }; | ||||
| 1015 | |||||
| 1016 | # Does it return a value in void context? | ||||
| 1017 | if (exists $attrs_ref->{VOID} || exists $attrs_ref->{DEFAULT}) { | ||||
| 1018 | push @values, { VOID => undef }; | ||||
| 1019 | } | ||||
| 1020 | else { | ||||
| 1021 | push @no_handler, 'VOID'; | ||||
| 1022 | } | ||||
| 1023 | |||||
| 1024 | # Generate list context value by "pretend" LIST handler... | ||||
| 1025 | push @values, { LIST => eval{ [ _internal_LIST(sub{}, $self) ] } // do{ chomp $@; "<<<Throws exception: $@>>>"} }; | ||||
| 1026 | _flag_self_ref_in($values[-1]{LIST}, $self); | ||||
| 1027 | |||||
| 1028 | # Generate scalar context values by calling appropriate handler... | ||||
| 1029 | push @values, $overloaded->( STR => q{""} ); | ||||
| 1030 | push @values, $overloaded->( NUM => '0+' ); | ||||
| 1031 | push @values, $overloaded->( BOOL => 'bool' ); | ||||
| 1032 | push @values, $overloaded->( SCALARREF => '${}' ); | ||||
| 1033 | _flag_self_ref_in($values[-1]{SCALARREF}, $self); | ||||
| 1034 | push @values, $overloaded->( ARRAYREF => '@{}' ); | ||||
| 1035 | _flag_self_ref_in($values[-1]{ARRAYREF}, $self); | ||||
| 1036 | push @values, $overloaded->( CODEREF => '&{}' ); | ||||
| 1037 | push @values, $overloaded->( HASHREF => '%{}' ); | ||||
| 1038 | push @values, $overloaded->( GLOBREF => '*{}' ); | ||||
| 1039 | |||||
| 1040 | # Are there handlers for various "generic" super-contexts... | ||||
| 1041 | my @fallbacks = grep { $attrs_ref->{$_} } | ||||
| 1042 | qw< DEFAULT NONVOID SCALAR VALUE REF RECOVER >; | ||||
| 1043 | |||||
| 1044 | push @values, { NO_HANDLER => \@no_handler }; | ||||
| 1045 | push @values, { FALLBACKS => \@fallbacks }; | ||||
| 1046 | |||||
| 1047 | # Temporarily replace object being dumped, by values found... | ||||
| 1048 | $_[0] = \@values; | ||||
| 1049 | } | ||||
| 1050 | |||||
| 1051 | # Call this method on a contextual return value object to debug it... | ||||
| 1052 | |||||
| 1053 | sub DUMP { | ||||
| 1054 | if (eval{ require Data::Dumper; 1; }) { | ||||
| 1055 | my ($crv) = @_; | ||||
| 1056 | if (eval{ ref($crv)->isa('Contextual::Return::Value')}) { | ||||
| 1057 | Contextual::Return::FREEZE($crv); | ||||
| 1058 | } | ||||
| 1059 | local $Data::Dumper::Terse = 1; | ||||
| 1060 | local $Data::Dumper::Indent = 1; | ||||
| 1061 | my $dump = Data::Dumper::Dumper($crv); | ||||
| 1062 | $dump =~ s<,\n \{><,ZZZZ{>msg; | ||||
| 1063 | $dump =~ s<\n\s+>< >msg; | ||||
| 1064 | $dump =~ s<,ZZZZ\{><\n {>msg; | ||||
| 1065 | return $dump; | ||||
| 1066 | } | ||||
| 1067 | else { | ||||
| 1068 | Carp::carp("Can't DUMP contextual return value (no Data::Dumper!)"); | ||||
| 1069 | return; | ||||
| 1070 | } | ||||
| 1071 | } | ||||
| 1072 | |||||
| 1073 | |||||
| 1074 | package Contextual::Return::Value; | ||||
| 1075 | 1 | 18µs | 1 | 4µs | # spent 4µs within Contextual::Return::Value::BEGIN@1075 which was called:
# once (4µs+0s) by IO::Prompter::BEGIN@9 at line 1075 # spent 4µs making 1 call to Contextual::Return::Value::BEGIN@1075 |
| 1076 | 2 | 42µs | 2 | 36µs | # spent 20µs (5+15) within Contextual::Return::Value::BEGIN@1076 which was called:
# once (5µs+15µs) by IO::Prompter::BEGIN@9 at line 1076 # spent 20µs making 1 call to Contextual::Return::Value::BEGIN@1076
# spent 15µs making 1 call to Exporter::import |
| 1077 | |||||
| 1078 | # spent 23µs within Contextual::Return::Value::BEGIN@1078 which was called:
# once (23µs+0s) by IO::Prompter::BEGIN@9 at line 1524 | ||||
| 1079 | %operator_impl = ( | ||||
| 1080 | q{""} => sub { | ||||
| 1081 | my ($self) = @_; | ||||
| 1082 | local $Contextual::Return::__RETOBJ__ = $self; | ||||
| 1083 | 2 | 187µs | 2 | 22µs | # spent 13µs (4+9) within Contextual::Return::Value::BEGIN@1083 which was called:
# once (4µs+9µs) by IO::Prompter::BEGIN@9 at line 1083 # spent 13µs making 1 call to Contextual::Return::Value::BEGIN@1083
# spent 9µs making 1 call to warnings::unimport |
| 1084 | |||||
| 1085 | my $attrs = $attrs_of{refaddr $self}; | ||||
| 1086 | handler: | ||||
| 1087 | for my $context (qw(STR SCALAR LAZY VALUE NONVOID DEFAULT NUM)) { | ||||
| 1088 | my $handler = $attrs->{$context} | ||||
| 1089 | or $attrs->{STRICT} and last handler | ||||
| 1090 | or next handler; | ||||
| 1091 | |||||
| 1092 | local $Contextual::Return::__RESULT__; | ||||
| 1093 | local $Contextual::Return::uplevel = 2; | ||||
| 1094 | my $rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 1095 | |||||
| 1096 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1097 | if (!$Contextual::Return::__RESULT__) { | ||||
| 1098 | $Contextual::Return::__RESULT__ = [$rv]; | ||||
| 1099 | } | ||||
| 1100 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1101 | } | ||||
| 1102 | elsif ($@) { | ||||
| 1103 | die $@; | ||||
| 1104 | } | ||||
| 1105 | |||||
| 1106 | if ($Contextual::Return::__RESULT__) { | ||||
| 1107 | $rv = $Contextual::Return::__RESULT__->[0]; | ||||
| 1108 | } | ||||
| 1109 | |||||
| 1110 | if ( $attrs->{FIXED} ) { | ||||
| 1111 | $_[0] = $rv; | ||||
| 1112 | } | ||||
| 1113 | elsif ( !$attrs->{ACTIVE} ) { | ||||
| 1114 | $attrs->{$context} = sub { $rv }; | ||||
| 1115 | } | ||||
| 1116 | return $rv; | ||||
| 1117 | } | ||||
| 1118 | $@ = _in_context "Can't use return value of $attrs->{sub} as a string"; | ||||
| 1119 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1120 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1121 | } | ||||
| 1122 | else { | ||||
| 1123 | die $@; | ||||
| 1124 | } | ||||
| 1125 | }, | ||||
| 1126 | |||||
| 1127 | q{0+} => sub { | ||||
| 1128 | my ($self) = @_; | ||||
| 1129 | local $Contextual::Return::__RETOBJ__ = $self; | ||||
| 1130 | 2 | 176µs | 2 | 24µs | # spent 14µs (5+9) within Contextual::Return::Value::BEGIN@1130 which was called:
# once (5µs+9µs) by IO::Prompter::BEGIN@9 at line 1130 # spent 14µs making 1 call to Contextual::Return::Value::BEGIN@1130
# spent 9µs making 1 call to warnings::unimport |
| 1131 | my $attrs = $attrs_of{refaddr $self}; | ||||
| 1132 | handler: | ||||
| 1133 | for my $context (qw(NUM SCALAR LAZY VALUE NONVOID DEFAULT STR)) { | ||||
| 1134 | my $handler = $attrs->{$context} | ||||
| 1135 | or $attrs->{STRICT} and last handler | ||||
| 1136 | or next handler; | ||||
| 1137 | |||||
| 1138 | local $Contextual::Return::__RESULT__; | ||||
| 1139 | local $Contextual::Return::uplevel = 2; | ||||
| 1140 | my $rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 1141 | |||||
| 1142 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1143 | if (!$Contextual::Return::__RESULT__) { | ||||
| 1144 | $Contextual::Return::__RESULT__ = [$rv]; | ||||
| 1145 | } | ||||
| 1146 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1147 | } | ||||
| 1148 | elsif ($@) { | ||||
| 1149 | die $@; | ||||
| 1150 | } | ||||
| 1151 | |||||
| 1152 | if ($Contextual::Return::__RESULT__) { | ||||
| 1153 | $rv = $Contextual::Return::__RESULT__->[0]; | ||||
| 1154 | } | ||||
| 1155 | |||||
| 1156 | if ( $attrs->{FIXED} ) { | ||||
| 1157 | $_[0] = $rv; | ||||
| 1158 | } | ||||
| 1159 | elsif ( !$attrs->{ACTIVE} ) { | ||||
| 1160 | $attrs->{$context} = sub { $rv }; | ||||
| 1161 | } | ||||
| 1162 | return $rv; | ||||
| 1163 | } | ||||
| 1164 | $@ = _in_context "Can't use return value of $attrs->{sub} as a number"; | ||||
| 1165 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1166 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1167 | } | ||||
| 1168 | else { | ||||
| 1169 | die $@; | ||||
| 1170 | } | ||||
| 1171 | }, | ||||
| 1172 | |||||
| 1173 | q{bool} => sub { | ||||
| 1174 | my ($self) = @_; | ||||
| 1175 | local $Contextual::Return::__RETOBJ__ = $self; | ||||
| 1176 | 2 | 252µs | 2 | 23µs | # spent 14µs (4+9) within Contextual::Return::Value::BEGIN@1176 which was called:
# once (4µs+9µs) by IO::Prompter::BEGIN@9 at line 1176 # spent 14µs making 1 call to Contextual::Return::Value::BEGIN@1176
# spent 9µs making 1 call to warnings::unimport |
| 1177 | my $attrs = $attrs_of{refaddr $self}; | ||||
| 1178 | |||||
| 1179 | # Handle Calls in Pure Boolean context... | ||||
| 1180 | my @PUREBOOL = $attrs->{want_pure_bool} ? ('PUREBOOL') : (); | ||||
| 1181 | $attrs->{want_pure_bool} = 0; | ||||
| 1182 | |||||
| 1183 | handler: | ||||
| 1184 | for my $context (@PUREBOOL, qw(BOOL STR NUM SCALAR LAZY VALUE NONVOID DEFAULT)) { | ||||
| 1185 | my $handler = $attrs->{$context} | ||||
| 1186 | or $context eq 'BOOL' and $attrs->{STRICT} and last handler | ||||
| 1187 | or next handler; | ||||
| 1188 | |||||
| 1189 | local $Contextual::Return::__RESULT__; | ||||
| 1190 | local $Contextual::Return::uplevel = 2; | ||||
| 1191 | my $outer_sig_warn = $SIG{__WARN__}; | ||||
| 1192 | local $SIG{__WARN__} | ||||
| 1193 | = sub{ return if $_[0] =~ /^Exiting \S+ via next/; | ||||
| 1194 | goto &{$outer_sig_warn} if $outer_sig_warn; | ||||
| 1195 | warn @_; | ||||
| 1196 | }; | ||||
| 1197 | my $rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 1198 | |||||
| 1199 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1200 | if (!$Contextual::Return::__RESULT__) { | ||||
| 1201 | $Contextual::Return::__RESULT__ = [$rv]; | ||||
| 1202 | } | ||||
| 1203 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1204 | } | ||||
| 1205 | elsif ($@) { | ||||
| 1206 | die $@; | ||||
| 1207 | } | ||||
| 1208 | |||||
| 1209 | if ($Contextual::Return::__RESULT__) { | ||||
| 1210 | $rv = $Contextual::Return::__RESULT__->[0]; | ||||
| 1211 | } | ||||
| 1212 | |||||
| 1213 | if ( $attrs->{FIXED} ) { | ||||
| 1214 | $_[0] = $rv; | ||||
| 1215 | } | ||||
| 1216 | elsif ( !$attrs->{ACTIVE} ) { | ||||
| 1217 | $attrs->{$context} = sub { $rv }; | ||||
| 1218 | } | ||||
| 1219 | return $rv; | ||||
| 1220 | } | ||||
| 1221 | $@ = _in_context "Can't use return value of $attrs->{sub} as a boolean"; | ||||
| 1222 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1223 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1224 | } | ||||
| 1225 | else { | ||||
| 1226 | die $@; | ||||
| 1227 | } | ||||
| 1228 | }, | ||||
| 1229 | '${}' => sub { | ||||
| 1230 | my ($self) = @_; | ||||
| 1231 | local $Contextual::Return::__RETOBJ__ = $self; | ||||
| 1232 | 2 | 216µs | 2 | 24µs | # spent 14µs (4+10) within Contextual::Return::Value::BEGIN@1232 which was called:
# once (4µs+10µs) by IO::Prompter::BEGIN@9 at line 1232 # spent 14µs making 1 call to Contextual::Return::Value::BEGIN@1232
# spent 10µs making 1 call to warnings::unimport |
| 1233 | my $attrs = $attrs_of{refaddr $self}; | ||||
| 1234 | handler: | ||||
| 1235 | for my $context (qw(SCALARREF REF NONVOID DEFAULT)) { | ||||
| 1236 | my $handler = $attrs->{$context} | ||||
| 1237 | or $attrs->{STRICT} and last handler | ||||
| 1238 | or next handler; | ||||
| 1239 | |||||
| 1240 | local $Contextual::Return::__RESULT__; | ||||
| 1241 | local $Contextual::Return::uplevel = 2; | ||||
| 1242 | my $rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 1243 | |||||
| 1244 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1245 | if (!$Contextual::Return::__RESULT__) { | ||||
| 1246 | $Contextual::Return::__RESULT__ = [$rv]; | ||||
| 1247 | } | ||||
| 1248 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1249 | } | ||||
| 1250 | elsif ($@) { | ||||
| 1251 | die $@; | ||||
| 1252 | } | ||||
| 1253 | |||||
| 1254 | if ($Contextual::Return::__RESULT__) { | ||||
| 1255 | $rv = $Contextual::Return::__RESULT__->[0]; | ||||
| 1256 | } | ||||
| 1257 | |||||
| 1258 | # Catch bad behaviour... | ||||
| 1259 | die _in_context "$context block did not return ", | ||||
| 1260 | "a suitable reference to the scalar dereference" | ||||
| 1261 | if ref($rv) ne 'SCALAR' && ref($rv) ne 'OBJ'; | ||||
| 1262 | |||||
| 1263 | if ( $attrs->{FIXED} ) { | ||||
| 1264 | $_[0] = $rv; | ||||
| 1265 | } | ||||
| 1266 | elsif ( !$attrs->{ACTIVE} ) { | ||||
| 1267 | $attrs->{$context} = sub { $rv }; | ||||
| 1268 | } | ||||
| 1269 | return $rv; | ||||
| 1270 | } | ||||
| 1271 | |||||
| 1272 | if ($attrs->{STRICT}) { | ||||
| 1273 | $@ = _in_context "Call to $attrs->{sub} didn't return a scalar reference, as required <LOC>"; | ||||
| 1274 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1275 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1276 | } | ||||
| 1277 | else { | ||||
| 1278 | die $@; | ||||
| 1279 | } | ||||
| 1280 | } | ||||
| 1281 | |||||
| 1282 | if ( $attrs->{FIXED} ) { | ||||
| 1283 | $_[0] = \$self; | ||||
| 1284 | } | ||||
| 1285 | return \$self; | ||||
| 1286 | }, | ||||
| 1287 | '@{}' => sub { | ||||
| 1288 | my ($self) = @_; | ||||
| 1289 | local $Contextual::Return::__RETOBJ__ = $self; | ||||
| 1290 | 2 | 298µs | 2 | 24µs | # spent 14µs (5+10) within Contextual::Return::Value::BEGIN@1290 which was called:
# once (5µs+10µs) by IO::Prompter::BEGIN@9 at line 1290 # spent 14µs making 1 call to Contextual::Return::Value::BEGIN@1290
# spent 10µs making 1 call to warnings::unimport |
| 1291 | my $attrs = $attrs_of{refaddr $self}; | ||||
| 1292 | local $Contextual::Return::__RESULT__; | ||||
| 1293 | handler: | ||||
| 1294 | for my $context (qw(ARRAYREF REF)) { | ||||
| 1295 | my $handler = $attrs->{$context} | ||||
| 1296 | or $attrs->{STRICT} and last handler | ||||
| 1297 | or next handler; | ||||
| 1298 | |||||
| 1299 | local $Contextual::Return::uplevel = 2; | ||||
| 1300 | my $rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 1301 | |||||
| 1302 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1303 | if (!$Contextual::Return::__RESULT__) { | ||||
| 1304 | $Contextual::Return::__RESULT__ = [$rv]; | ||||
| 1305 | } | ||||
| 1306 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1307 | } | ||||
| 1308 | elsif ($@) { | ||||
| 1309 | die $@; | ||||
| 1310 | } | ||||
| 1311 | |||||
| 1312 | if ($Contextual::Return::__RESULT__) { | ||||
| 1313 | $rv = $Contextual::Return::__RESULT__->[0]; | ||||
| 1314 | } | ||||
| 1315 | |||||
| 1316 | # Catch bad behaviour... | ||||
| 1317 | die _in_context "$context block did not return ", | ||||
| 1318 | "a suitable reference to the array dereference" | ||||
| 1319 | if ref($rv) ne 'ARRAY' && ref($rv) ne 'OBJ'; | ||||
| 1320 | |||||
| 1321 | if ( $attrs->{FIXED} ) { | ||||
| 1322 | $_[0] = $rv; | ||||
| 1323 | } | ||||
| 1324 | elsif ( !$attrs->{ACTIVE} ) { | ||||
| 1325 | $attrs->{$context} = sub { $rv }; | ||||
| 1326 | } | ||||
| 1327 | return $rv; | ||||
| 1328 | } | ||||
| 1329 | handler: | ||||
| 1330 | for my $context (qw(LIST VALUE NONVOID DEFAULT)) { | ||||
| 1331 | last handler if $attrs->{STRICT}; | ||||
| 1332 | my $handler = $attrs->{$context} | ||||
| 1333 | or next handler; | ||||
| 1334 | |||||
| 1335 | local $Contextual::Return::uplevel = 2; | ||||
| 1336 | my @rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 1337 | |||||
| 1338 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1339 | if (!$Contextual::Return::__RESULT__) { | ||||
| 1340 | $Contextual::Return::__RESULT__ = [@rv]; | ||||
| 1341 | } | ||||
| 1342 | () = $recover->(@{$attrs->{args}}); | ||||
| 1343 | } | ||||
| 1344 | elsif ($@) { | ||||
| 1345 | die $@; | ||||
| 1346 | } | ||||
| 1347 | |||||
| 1348 | if ($Contextual::Return::__RESULT__) { | ||||
| 1349 | @rv = @{$Contextual::Return::__RESULT__->[0]}; | ||||
| 1350 | } | ||||
| 1351 | |||||
| 1352 | if ( $attrs->{FIXED} ) { | ||||
| 1353 | $_[0] = \@rv; | ||||
| 1354 | } | ||||
| 1355 | elsif ( !$attrs->{ACTIVE} ) { | ||||
| 1356 | $attrs->{$context} = sub { @rv }; | ||||
| 1357 | } | ||||
| 1358 | return \@rv; | ||||
| 1359 | } | ||||
| 1360 | |||||
| 1361 | if ($attrs->{STRICT}) { | ||||
| 1362 | $@ = _in_context "Call to $attrs->{sub} didn't return an array reference, as required <LOC>"; | ||||
| 1363 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1364 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1365 | } | ||||
| 1366 | else { | ||||
| 1367 | die $@; | ||||
| 1368 | } | ||||
| 1369 | } | ||||
| 1370 | |||||
| 1371 | return [ $self ]; | ||||
| 1372 | }, | ||||
| 1373 | '%{}' => sub { | ||||
| 1374 | my ($self) = @_; | ||||
| 1375 | local $Contextual::Return::__RETOBJ__ = $self; | ||||
| 1376 | 2 | 210µs | 2 | 24µs | # spent 14µs (4+10) within Contextual::Return::Value::BEGIN@1376 which was called:
# once (4µs+10µs) by IO::Prompter::BEGIN@9 at line 1376 # spent 14µs making 1 call to Contextual::Return::Value::BEGIN@1376
# spent 10µs making 1 call to warnings::unimport |
| 1377 | my $attrs = $attrs_of{refaddr $self}; | ||||
| 1378 | handler: | ||||
| 1379 | for my $context (qw(HASHREF REF NONVOID DEFAULT)) { | ||||
| 1380 | my $handler = $attrs->{$context} | ||||
| 1381 | or $attrs->{STRICT} and last handler | ||||
| 1382 | or next handler; | ||||
| 1383 | |||||
| 1384 | local $Contextual::Return::__RESULT__; | ||||
| 1385 | local $Contextual::Return::uplevel = 2; | ||||
| 1386 | my $rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 1387 | |||||
| 1388 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1389 | if (!$Contextual::Return::__RESULT__) { | ||||
| 1390 | $Contextual::Return::__RESULT__ = [$rv]; | ||||
| 1391 | } | ||||
| 1392 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1393 | } | ||||
| 1394 | elsif ($@) { | ||||
| 1395 | die $@; | ||||
| 1396 | } | ||||
| 1397 | |||||
| 1398 | if ($Contextual::Return::__RESULT__) { | ||||
| 1399 | $rv = $Contextual::Return::__RESULT__->[0]; | ||||
| 1400 | } | ||||
| 1401 | |||||
| 1402 | # Catch bad behaviour... | ||||
| 1403 | die _in_context "$context block did not return ", | ||||
| 1404 | "a suitable reference to the hash dereference" | ||||
| 1405 | if ref($rv) ne 'HASH' && ref($rv) ne 'OBJ'; | ||||
| 1406 | |||||
| 1407 | if ( $attrs->{FIXED} ) { | ||||
| 1408 | $_[0] = $rv; | ||||
| 1409 | } | ||||
| 1410 | elsif ( !$attrs->{ACTIVE} ) { | ||||
| 1411 | $attrs->{$context} = sub { $rv }; | ||||
| 1412 | } | ||||
| 1413 | return $rv; | ||||
| 1414 | } | ||||
| 1415 | $@ = _in_context "Call to $attrs->{sub} didn't return a hash reference, as required <LOC>"; | ||||
| 1416 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1417 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1418 | } | ||||
| 1419 | else { | ||||
| 1420 | die $@; | ||||
| 1421 | } | ||||
| 1422 | }, | ||||
| 1423 | '&{}' => sub { | ||||
| 1424 | my ($self) = @_; | ||||
| 1425 | local $Contextual::Return::__RETOBJ__ = $self; | ||||
| 1426 | 2 | 200µs | 2 | 31µs | # spent 21µs (11+10) within Contextual::Return::Value::BEGIN@1426 which was called:
# once (11µs+10µs) by IO::Prompter::BEGIN@9 at line 1426 # spent 21µs making 1 call to Contextual::Return::Value::BEGIN@1426
# spent 10µs making 1 call to warnings::unimport |
| 1427 | my $attrs = $attrs_of{refaddr $self}; | ||||
| 1428 | handler: | ||||
| 1429 | for my $context (qw(CODEREF REF NONVOID DEFAULT)) { | ||||
| 1430 | my $handler = $attrs->{$context} | ||||
| 1431 | or $attrs->{STRICT} and last handler | ||||
| 1432 | or next handler; | ||||
| 1433 | |||||
| 1434 | local $Contextual::Return::__RESULT__; | ||||
| 1435 | local $Contextual::Return::uplevel = 2; | ||||
| 1436 | my $rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 1437 | |||||
| 1438 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1439 | if (!$Contextual::Return::__RESULT__) { | ||||
| 1440 | $Contextual::Return::__RESULT__ = [$rv]; | ||||
| 1441 | } | ||||
| 1442 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1443 | } | ||||
| 1444 | elsif ($@) { | ||||
| 1445 | die $@; | ||||
| 1446 | } | ||||
| 1447 | |||||
| 1448 | if ($Contextual::Return::__RESULT__) { | ||||
| 1449 | $rv = $Contextual::Return::__RESULT__->[0]; | ||||
| 1450 | } | ||||
| 1451 | |||||
| 1452 | # Catch bad behaviour... | ||||
| 1453 | die _in_context "$context block did not return ", | ||||
| 1454 | "a suitable reference to the subroutine dereference" | ||||
| 1455 | if ref($rv) ne 'CODE' && ref($rv) ne 'OBJ'; | ||||
| 1456 | |||||
| 1457 | if ( $attrs->{FIXED} ) { | ||||
| 1458 | $_[0] = $rv; | ||||
| 1459 | } | ||||
| 1460 | elsif ( !$attrs->{ACTIVE} ) { | ||||
| 1461 | $attrs->{$context} = sub { $rv }; | ||||
| 1462 | } | ||||
| 1463 | return $rv; | ||||
| 1464 | } | ||||
| 1465 | $@ = _in_context "Call to $attrs->{sub} didn't return a subroutine reference, as required <LOC>"; | ||||
| 1466 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1467 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1468 | } | ||||
| 1469 | else { | ||||
| 1470 | die $@; | ||||
| 1471 | } | ||||
| 1472 | }, | ||||
| 1473 | '*{}' => sub { | ||||
| 1474 | my ($self) = @_; | ||||
| 1475 | local $Contextual::Return::__RETOBJ__ = $self; | ||||
| 1476 | 2 | 182µs | 2 | 25µs | # spent 15µs (5+10) within Contextual::Return::Value::BEGIN@1476 which was called:
# once (5µs+10µs) by IO::Prompter::BEGIN@9 at line 1476 # spent 15µs making 1 call to Contextual::Return::Value::BEGIN@1476
# spent 10µs making 1 call to warnings::unimport |
| 1477 | my $attrs = $attrs_of{refaddr $self}; | ||||
| 1478 | handler: | ||||
| 1479 | for my $context (qw(GLOBREF REF NONVOID DEFAULT)) { | ||||
| 1480 | my $handler = $attrs->{$context} | ||||
| 1481 | or $attrs->{STRICT} and last handler | ||||
| 1482 | or next handler; | ||||
| 1483 | |||||
| 1484 | local $Contextual::Return::__RESULT__; | ||||
| 1485 | local $Contextual::Return::uplevel = 2; | ||||
| 1486 | my $rv = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 1487 | |||||
| 1488 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1489 | if (!$Contextual::Return::__RESULT__) { | ||||
| 1490 | $Contextual::Return::__RESULT__ = [$rv]; | ||||
| 1491 | } | ||||
| 1492 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1493 | } | ||||
| 1494 | elsif ($@) { | ||||
| 1495 | die $@; | ||||
| 1496 | } | ||||
| 1497 | |||||
| 1498 | if ($Contextual::Return::__RESULT__) { | ||||
| 1499 | $rv = $Contextual::Return::__RESULT__->[0]; | ||||
| 1500 | } | ||||
| 1501 | |||||
| 1502 | # Catch bad behaviour... | ||||
| 1503 | die _in_context "$context block did not return ", | ||||
| 1504 | "a suitable reference to the typeglob dereference" | ||||
| 1505 | if ref($rv) ne 'GLOB' && ref($rv) ne 'OBJ'; | ||||
| 1506 | |||||
| 1507 | if ( $attrs->{FIXED} ) { | ||||
| 1508 | $_[0] = $rv; | ||||
| 1509 | } | ||||
| 1510 | elsif ( !$attrs->{ACTIVE} ) { | ||||
| 1511 | $attrs->{$context} = sub { $rv }; | ||||
| 1512 | } | ||||
| 1513 | return $rv; | ||||
| 1514 | } | ||||
| 1515 | $@ = _in_context "Call to $attrs->{sub} didn't return a typeglob reference, as required <LOC>"; | ||||
| 1516 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1517 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1518 | } | ||||
| 1519 | else { | ||||
| 1520 | die $@; | ||||
| 1521 | } | ||||
| 1522 | }, | ||||
| 1523 | 1 | 24µs | ); | ||
| 1524 | 1 | 15µs | 1 | 23µs | } # spent 23µs making 1 call to Contextual::Return::Value::BEGIN@1078 |
| 1525 | |||||
| 1526 | 2 | 35µs | 2 | 68µs | # spent 37µs (6+31) within Contextual::Return::Value::BEGIN@1526 which was called:
# once (6µs+31µs) by IO::Prompter::BEGIN@9 at line 1526 # spent 37µs making 1 call to Contextual::Return::Value::BEGIN@1526
# spent 31µs making 1 call to overload::import |
| 1527 | |||||
| 1528 | sub DESTROY { | ||||
| 1529 | my ($id) = refaddr shift; | ||||
| 1530 | my $attrs = $attrs_of{$id}; | ||||
| 1531 | 2 | 199µs | 2 | 24µs | # spent 14µs (4+10) within Contextual::Return::Value::BEGIN@1531 which was called:
# once (4µs+10µs) by IO::Prompter::BEGIN@9 at line 1531 # spent 14µs making 1 call to Contextual::Return::Value::BEGIN@1531
# spent 10µs making 1 call to warnings::unimport |
| 1532 | if (my $handler = $attrs->{CLEANUP}) { | ||||
| 1533 | $handler->(@{ $attrs->{args} }); | ||||
| 1534 | } | ||||
| 1535 | delete $attrs_of{$id}; | ||||
| 1536 | return; | ||||
| 1537 | } | ||||
| 1538 | |||||
| 1539 | 1 | 2µs | 1 | 400ns | my $NO_SUCH_METHOD = qr/\ACan't (?:locate|call)(?: class| object)? method/ms; # spent 400ns making 1 call to Contextual::Return::Value::CORE:qr |
| 1540 | |||||
| 1541 | # Forward metainformation requests to actual class... | ||||
| 1542 | sub can { | ||||
| 1543 | my ($invocant) = @_; | ||||
| 1544 | # Only forward requests on actual C::R::V objects... | ||||
| 1545 | if (ref $invocant) { | ||||
| 1546 | our $AUTOLOAD = 'can'; | ||||
| 1547 | goto &AUTOLOAD; | ||||
| 1548 | } | ||||
| 1549 | |||||
| 1550 | # Refer requests on classes to actual class hierarchy... | ||||
| 1551 | return $invocant->SUPER::can(@_[1..$#_]); | ||||
| 1552 | } | ||||
| 1553 | |||||
| 1554 | sub isa { | ||||
| 1555 | # Only forward requests on actual C::R::V objects... | ||||
| 1556 | my ($invocant) = @_; | ||||
| 1557 | if (ref $invocant) { | ||||
| 1558 | our $AUTOLOAD = 'isa'; | ||||
| 1559 | goto &AUTOLOAD; | ||||
| 1560 | } | ||||
| 1561 | |||||
| 1562 | # Refer requests on classes to actual class hierarchy... | ||||
| 1563 | return $invocant->SUPER::isa(@_[1..$#_]); | ||||
| 1564 | } | ||||
| 1565 | |||||
| 1566 | |||||
| 1567 | sub AUTOLOAD { | ||||
| 1568 | my ($self) = @_; | ||||
| 1569 | our $AUTOLOAD; | ||||
| 1570 | |||||
| 1571 | my ($requested_method) = $AUTOLOAD =~ m{ .* :: (.*) }xms ? $1 : $AUTOLOAD; | ||||
| 1572 | |||||
| 1573 | my $attrs = $attrs_of{refaddr $self} || {}; | ||||
| 1574 | local $Contextual::Return::__RETOBJ__ = $self; | ||||
| 1575 | 2 | 436µs | 2 | 25µs | # spent 15µs (5+10) within Contextual::Return::Value::BEGIN@1575 which was called:
# once (5µs+10µs) by IO::Prompter::BEGIN@9 at line 1575 # spent 15µs making 1 call to Contextual::Return::Value::BEGIN@1575
# spent 10µs making 1 call to warnings::unimport |
| 1576 | |||||
| 1577 | # First, see if there is a method call handler... | ||||
| 1578 | if (my $context_handler = $attrs->{METHOD}) { | ||||
| 1579 | local $Contextual::Return::__RESULT__; | ||||
| 1580 | local $Contextual::Return::uplevel = 2; | ||||
| 1581 | my @method_handlers = eval { $context_handler->(@{$attrs->{args}}) }; | ||||
| 1582 | |||||
| 1583 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1584 | if (!$Contextual::Return::__RESULT__) { | ||||
| 1585 | $Contextual::Return::__RESULT__ = [\@method_handlers]; | ||||
| 1586 | } | ||||
| 1587 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1588 | } | ||||
| 1589 | elsif ($@) { | ||||
| 1590 | die $@; | ||||
| 1591 | } | ||||
| 1592 | |||||
| 1593 | if ($Contextual::Return::__RESULT__) { | ||||
| 1594 | @method_handlers = @{$Contextual::Return::__RESULT__}; | ||||
| 1595 | } | ||||
| 1596 | |||||
| 1597 | # Locate the correct method handler (if any)... | ||||
| 1598 | MATCHER: | ||||
| 1599 | while (my ($matcher, $method_handler) = splice @method_handlers, 0, 2) { | ||||
| 1600 | |||||
| 1601 | if (ref($matcher) eq 'ARRAY') { | ||||
| 1602 | next MATCHER | ||||
| 1603 | if !grep { $requested_method =~ $_ } @{$matcher}; | ||||
| 1604 | } | ||||
| 1605 | elsif ($requested_method !~ $matcher) { | ||||
| 1606 | next MATCHER; | ||||
| 1607 | } | ||||
| 1608 | |||||
| 1609 | shift; | ||||
| 1610 | if (wantarray) { | ||||
| 1611 | my @result = eval { | ||||
| 1612 | local $_ = $requested_method; | ||||
| 1613 | $method_handler->($self,@_); | ||||
| 1614 | }; | ||||
| 1615 | die _in_context $@ if $@; | ||||
| 1616 | return @result; | ||||
| 1617 | } | ||||
| 1618 | else { | ||||
| 1619 | my $result = eval { | ||||
| 1620 | local $_ = $requested_method; | ||||
| 1621 | $method_handler->($self,@_); | ||||
| 1622 | }; | ||||
| 1623 | die _in_context $@ if $@; | ||||
| 1624 | return $result; | ||||
| 1625 | } | ||||
| 1626 | } | ||||
| 1627 | } | ||||
| 1628 | |||||
| 1629 | # Next, try to create an object on which to call the method... | ||||
| 1630 | handler: | ||||
| 1631 | for my $context (qw(OBJREF STR SCALAR LAZY VALUE NONVOID DEFAULT)) { | ||||
| 1632 | my $handler = $attrs->{$context} | ||||
| 1633 | or $attrs->{STRICT} and last handler | ||||
| 1634 | or next handler; | ||||
| 1635 | |||||
| 1636 | local $Contextual::Return::__RESULT__; | ||||
| 1637 | local $Contextual::Return::uplevel = 2; | ||||
| 1638 | my $object = eval { $handler->(@{$attrs->{args}}) }; | ||||
| 1639 | |||||
| 1640 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1641 | if (!$Contextual::Return::__RESULT__) { | ||||
| 1642 | $Contextual::Return::__RESULT__ = [$object]; | ||||
| 1643 | } | ||||
| 1644 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1645 | } | ||||
| 1646 | elsif ($@) { | ||||
| 1647 | die $@; | ||||
| 1648 | } | ||||
| 1649 | |||||
| 1650 | if ($Contextual::Return::__RESULT__) { | ||||
| 1651 | $object = $Contextual::Return::__RESULT__->[0]; | ||||
| 1652 | } | ||||
| 1653 | |||||
| 1654 | if ( $attrs->{FIXED} ) { | ||||
| 1655 | $_[0] = $object; | ||||
| 1656 | } | ||||
| 1657 | elsif ( !$attrs->{ACTIVE} ) { | ||||
| 1658 | $attrs->{$context} = sub { $object }; | ||||
| 1659 | } | ||||
| 1660 | shift; | ||||
| 1661 | |||||
| 1662 | if (wantarray) { | ||||
| 1663 | my @result = eval { $object->$requested_method(@_) }; | ||||
| 1664 | my $exception = $@; | ||||
| 1665 | return @result if !$exception; | ||||
| 1666 | die _in_context $exception if $exception !~ $NO_SUCH_METHOD; | ||||
| 1667 | } | ||||
| 1668 | else { | ||||
| 1669 | my $result = eval { $object->$requested_method(@_) }; | ||||
| 1670 | my $exception = $@; | ||||
| 1671 | return $result if !$exception; | ||||
| 1672 | die _in_context $exception if $exception !~ $NO_SUCH_METHOD; | ||||
| 1673 | } | ||||
| 1674 | $@ = _in_context "Can't call method '$requested_method' on $context value returned by $attrs->{sub}"; | ||||
| 1675 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1676 | scalar $recover->(@{$attrs->{args}}); | ||||
| 1677 | } | ||||
| 1678 | else { | ||||
| 1679 | die $@; | ||||
| 1680 | } | ||||
| 1681 | } | ||||
| 1682 | |||||
| 1683 | # Otherwise, the method cannot be called, so react accordingly... | ||||
| 1684 | $@ = _in_context "Can't call method '$requested_method' on value returned by $attrs->{sub}"; | ||||
| 1685 | if (my $recover = $attrs->{RECOVER}) { | ||||
| 1686 | return scalar $recover->(@{$attrs->{args}}); | ||||
| 1687 | } | ||||
| 1688 | else { | ||||
| 1689 | die $@; | ||||
| 1690 | } | ||||
| 1691 | } | ||||
| 1692 | |||||
| 1693 | package Contextual::Return::Lvalue; | ||||
| 1694 | |||||
| 1695 | sub TIESCALAR { | ||||
| 1696 | my ($package, @handler) = @_; | ||||
| 1697 | return bless {@handler}, $package; | ||||
| 1698 | } | ||||
| 1699 | |||||
| 1700 | # Handle calls that are lvalues... | ||||
| 1701 | sub STORE { | ||||
| 1702 | local *CALLER::_ = \$_; | ||||
| 1703 | local *_ = \$_[1]; | ||||
| 1704 | local $Contextual::Return::uplevel = 1; | ||||
| 1705 | 2 | 64µs | 2 | 24µs | # spent 14µs (5+10) within Contextual::Return::Lvalue::BEGIN@1705 which was called:
# once (5µs+10µs) by IO::Prompter::BEGIN@9 at line 1705 # spent 14µs making 1 call to Contextual::Return::Lvalue::BEGIN@1705
# spent 10µs making 1 call to warnings::unimport |
| 1706 | local $Contextual::Return::__RESULT__; | ||||
| 1707 | |||||
| 1708 | my $rv = $_[0]{LVALUE}( @{$_[0]{args}} ); | ||||
| 1709 | |||||
| 1710 | return $rv if !$Contextual::Return::__RESULT__; | ||||
| 1711 | return $Contextual::Return::__RESULT__->[0]; | ||||
| 1712 | } | ||||
| 1713 | |||||
| 1714 | # Handle calls that are rvalues... | ||||
| 1715 | sub FETCH { | ||||
| 1716 | local $Contextual::Return::uplevel = 1; | ||||
| 1717 | 2 | 111µs | 2 | 20µs | # spent 12µs (4+8) within Contextual::Return::Lvalue::BEGIN@1717 which was called:
# once (4µs+8µs) by IO::Prompter::BEGIN@9 at line 1717 # spent 12µs making 1 call to Contextual::Return::Lvalue::BEGIN@1717
# spent 8µs making 1 call to warnings::unimport |
| 1718 | local $Contextual::Return::__RESULT__; | ||||
| 1719 | |||||
| 1720 | my $rv = $_[0]{RVALUE} ? $_[0]{RVALUE}( @{$_[0]{args}} ) : undef; | ||||
| 1721 | |||||
| 1722 | return $rv if !$Contextual::Return::__RESULT__; | ||||
| 1723 | return $Contextual::Return::__RESULT__->[0]; | ||||
| 1724 | } | ||||
| 1725 | |||||
| 1726 | sub DESTROY {}; | ||||
| 1727 | |||||
| 1728 | 1 | 12µs | 1; # Magic true value required at end of module | ||
| 1729 | |||||
| 1730 | __END__ | ||||
# spent 2µs within Contextual::Return::CORE:qr which was called:
# once (2µs+0s) by IO::Prompter::BEGIN@9 at line 957 | |||||
# spent 400ns within Contextual::Return::Value::CORE:qr which was called:
# once (400ns+0s) by IO::Prompter::BEGIN@9 at line 1539 |