| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Exception::Class::TCF; | 
| 2 |  |  |  |  |  |  | use Exception::Class ( | 
| 3 | 1 |  |  |  |  | 10 | 'Exception::Class::TCF' => { | 
| 4 |  |  |  |  |  |  | 'isa'    => 'Exception::Class::Base', | 
| 5 |  |  |  |  |  |  | 'fields' => ['Message'] | 
| 6 |  |  |  |  |  |  | } | 
| 7 | 1 |  |  | 1 |  | 2088 | ); | 
|  | 1 |  |  |  |  | 31269 |  | 
| 8 | 1 |  |  | 1 |  | 715 | use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION); | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 4277 |  | 
| 9 |  |  |  |  |  |  | require Exporter; | 
| 10 |  |  |  |  |  |  | @ISA       = qw(Exporter Exception::Class::Base); | 
| 11 |  |  |  |  |  |  | @EXPORT    = qw(&try &catch &throw &finally); | 
| 12 |  |  |  |  |  |  | @EXPORT_OK = qw(&isThrowing &deactivate &handleWarn &handleDie &make); | 
| 13 |  |  |  |  |  |  | $VERSION   = '0.03'; | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | my $DEFAULT_UNCAUGHT = "Exception of type %s thrown but not caught"; | 
| 16 |  |  |  |  |  |  | my %PROTECTED = map { $_ => 1 } qw(Message); | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | sub UNIVERSAL::throw (@) { | 
| 19 | 0 |  |  | 0 | 0 | 0 | my ( $pack, $file, $line ) = caller; | 
| 20 | 0 |  |  |  |  | 0 | warn "Parsing problem with throw at $file line $line.\n"; | 
| 21 | 0 |  |  |  |  | 0 | &Exception::Class::TCF::throw(@_) | 
| 22 |  |  |  |  |  |  | } | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | sub UNIVERSAL::make (@) { | 
| 25 | 0 |  |  | 0 | 0 | 0 | my($pack,$file,$line) = caller; | 
| 26 | 0 |  |  |  |  | 0 | warn "Parsing problem with throw at $file line $line.\n"; | 
| 27 | 0 |  |  |  |  | 0 | &Exception::Class::TCF::make(@_) | 
| 28 |  |  |  |  |  |  | } | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | sub UNIVERSAL::catch (@) { | 
| 31 | 0 |  |  | 0 | 0 | 0 | &Exception::Class::TCF::catch(@_) | 
| 32 |  |  |  |  |  |  | } | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | sub isException { | 
| 35 | 27 |  |  | 27 | 0 | 49 | my $class = shift; | 
| 36 | 27 | 50 |  |  |  | 100 | $class = ref $class if ref $class; | 
| 37 | 27 |  |  |  |  | 49 | &isBelow($class,'Exception::Class::TCF'); | 
| 38 |  |  |  |  |  |  | } | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | sub isBelow { | 
| 41 | 65 |  |  | 65 | 0 | 84 | my($class,$above) = @_; | 
| 42 | 65 | 100 |  |  |  | 714 | $class->isa($above) || $class->isa('Exception::Class::TCF::'.$above); | 
| 43 |  |  |  |  |  |  | } | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | sub new { | 
| 46 | 31 |  |  | 31 | 1 | 44 | my($class) = shift; | 
| 47 | 31 | 100 |  |  |  | 70 | unshift @_,'Message' if @_ % 2; | 
| 48 | 31 |  |  |  |  | 59 | my %args = @_; | 
| 49 | 31 |  |  |  |  | 176 | my $self = $class->SUPER::new( 'Message' => $args{'Message'} ); | 
| 50 | 31 |  |  |  |  | 15190 | bless $self, $class; | 
| 51 | 31 |  |  |  |  | 95 | for my $key ( keys %args ) { | 
| 52 | 4 | 50 |  |  |  | 30 | if ( $key ne 'Message' ) { | 
| 53 | 0 |  |  |  |  | 0 | $self->setFields( $key, $args{$key} ); | 
| 54 |  |  |  |  |  |  | } | 
| 55 |  |  |  |  |  |  | } | 
| 56 | 31 |  |  |  |  | 93 | return $self; | 
| 57 |  |  |  |  |  |  | } | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | sub make { | 
| 60 | 27 |  |  | 27 | 1 | 44 | my $class = shift; | 
| 61 | 27 | 50 |  |  |  | 68 | unless ($class =~ m/^Exception::Class::TCF::/o) { | 
| 62 | 27 |  |  |  |  | 89 | my $fclass = 'Exception::Class::TCF::' . $class; | 
| 63 | 27 | 50 |  |  |  | 55 | $class = $fclass if isException($fclass); | 
| 64 |  |  |  |  |  |  | } | 
| 65 | 27 |  |  |  |  | 139 | return $class->new(@_); | 
| 66 |  |  |  |  |  |  | } | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | sub type { | 
| 69 | 21 |  | 33 | 21 | 1 | 172 | my $type = ref($_[0]) || $_[0]; | 
| 70 | 21 |  |  |  |  | 62 | $type =~ s/^Exception::Class::TCF:://o; | 
| 71 | 21 |  |  |  |  | 58 | return $type; | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | sub setFields { | 
| 75 | 0 |  |  | 0 | 1 | 0 | my($self) = shift; | 
| 76 | 0 | 0 |  |  |  | 0 | if (ref $self) { | 
| 77 | 0 |  |  |  |  | 0 | my ( $key, $val ); | 
| 78 | 0 |  |  |  |  | 0 | while ( ( $key, $val ) = splice @_, 2, 0 ) { | 
| 79 | 0 | 0 |  |  |  | 0 | next if $self->isProtected($val); | 
| 80 | 0 |  |  |  |  | 0 | $self->{$key} = $val; | 
| 81 |  |  |  |  |  |  | } | 
| 82 |  |  |  |  |  |  | } | 
| 83 | 0 |  |  |  |  | 0 | return $self; | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | sub hasField { | 
| 87 | 4 | 50 |  | 4 | 1 | 30 | ref($_[0]) && exists $_[0]->{$_[1]}; | 
| 88 |  |  |  |  |  |  | } | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 0 |  |  | 0 | 1 | 0 | sub protectedFields { keys %PROTECTED } | 
| 91 | 0 |  |  | 0 | 0 | 0 | sub isProtected { exists $PROTECTED{$_[1]} } | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | sub removeFields { | 
| 94 | 0 |  |  | 0 | 1 | 0 | my($self) = shift; | 
| 95 | 0 | 0 |  |  |  | 0 | if (ref $self) { | 
| 96 | 0 |  |  |  |  | 0 | my($name); | 
| 97 | 0 |  |  |  |  | 0 | foreach ($name) { | 
| 98 | 0 | 0 |  |  |  | 0 | next if $PROTECTED{$name}; | 
| 99 | 0 |  |  |  |  | 0 | delete $self->{$name}; | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  | } | 
| 102 | 0 |  |  |  |  | 0 | return $self; | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | sub getField { | 
| 106 | 0 | 0 |  | 0 | 1 | 0 | ref($_[0]) && $_[0]->{$_[1]}; | 
| 107 |  |  |  |  |  |  | } | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | sub setMessage { | 
| 110 | 1 |  |  | 1 | 1 | 10 | my ( $self, $msg ) = @_; | 
| 111 | 1 | 50 |  |  |  | 5 | if (ref $self) { | 
| 112 | 1 |  |  |  |  | 2 | $self->{'Message'} = $msg; | 
| 113 |  |  |  |  |  |  | } | 
| 114 | 1 |  |  |  |  | 3 | return $self; | 
| 115 |  |  |  |  |  |  | } | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | sub message { | 
| 118 | 5 | 50 | 33 | 5 | 1 | 68 | ref($_[0]) && exists $_[0]->{'Message'} && $_[0]->{'Message'}; | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | my $dTHROWING; | 
| 122 |  |  |  |  |  |  | my ( @ARGS, $EXCEPTION, $CATCHING, $THROWING, @STACK ); | 
| 123 |  |  |  |  |  |  | my ( $HANDLE_DIE, $HANDLE_WARN ); | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | ###  These variables are used for the following purposes: | 
| 126 |  |  |  |  |  |  | ###  $EXCEPTION | 
| 127 |  |  |  |  |  |  | ###    contains the current active exception and | 
| 128 |  |  |  |  |  |  | ###  @ARGS | 
| 129 |  |  |  |  |  |  | ###    the remaining arguments to the throw that threw it. | 
| 130 |  |  |  |  |  |  | ###  $CATCHING | 
| 131 |  |  |  |  |  |  | ###    tells if we're in a handler (but haven't entered any | 
| 132 |  |  |  |  |  |  | ###    try blocks in the handler). | 
| 133 |  |  |  |  |  |  | ###  $THROWING | 
| 134 |  |  |  |  |  |  | ###    tells if we have an active exception. | 
| 135 |  |  |  |  |  |  | ###  $dTHROWING | 
| 136 |  |  |  |  |  |  | ###    is used for shortlived communication between throw and try, | 
| 137 |  |  |  |  |  |  | ###    it is often the same as $THROWING but not always. | 
| 138 |  |  |  |  |  |  | ###  @STACK | 
| 139 |  |  |  |  |  |  | ###    is used for the stack needed to implement the scoping rules | 
| 140 |  |  |  |  |  |  | ###    for the active exception. | 
| 141 |  |  |  |  |  |  | ###  $HANDLE_DIE | 
| 142 |  |  |  |  |  |  | ###    set if an ordinary die should be considered as throwing | 
| 143 |  |  |  |  |  |  | ###    a Die exception | 
| 144 |  |  |  |  |  |  | ###  $HANDLE_WARN | 
| 145 |  |  |  |  |  |  | ###    set if a warn should be considered as throwing | 
| 146 |  |  |  |  |  |  | ###    a Warning exception | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | sub handleDie { | 
| 149 | 1 |  |  | 1 | 1 | 54 | $HANDLE_DIE = defined $_[0]; | 
| 150 |  |  |  |  |  |  | } | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | sub handleWarn { | 
| 153 | 0 |  |  | 0 | 1 | 0 | my $oldhw = $HANDLE_WARN; | 
| 154 | 0 |  |  |  |  | 0 | $HANDLE_WARN = $_[0]; | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | sub deactivate { | 
| 158 | 0 | 0 |  | 0 | 1 | 0 | if ($THROWING) { | 
| 159 | 0 |  |  |  |  | 0 | undef $EXCEPTION; | 
| 160 | 0 |  |  |  |  | 0 | undef @ARGS; | 
| 161 | 0 |  |  |  |  | 0 | $THROWING = $CATCHING = 0; | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | sub dieMess { | 
| 166 | 4 |  |  | 4 | 0 | 7 | my($self) = @_; | 
| 167 | 4 |  |  |  |  | 9 | my($type) = $self->type; | 
| 168 | 4 |  |  |  |  | 8 | my $UNCAUGHT = $DEFAULT_UNCAUGHT; | 
| 169 | 4 | 50 |  |  |  | 23 | if ($self->hasField('DyingMessage')) { | 
| 170 | 0 |  |  |  |  | 0 | $UNCAUGHT = $self->getField('DyingMessage'); | 
| 171 |  |  |  |  |  |  | } | 
| 172 | 4 |  |  |  |  | 15 | my $mess = sprintf $UNCAUGHT, $type; | 
| 173 | 4 | 50 |  |  |  | 14 | if ( $mess =~ m/\n$/o ) { | 
| 174 | 0 |  |  |  |  | 0 | return $mess; | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  | else { | 
| 177 | 4 |  |  |  |  | 21 | my ( $pack, $file, $line ) = caller 2; | 
| 178 | 4 | 50 |  |  |  | 22 | ( $pack, $file, $line ) = caller 3 if ($pack eq 'Exception::Class::TCF'); | 
| 179 | 4 |  |  |  |  | 66 | return "$mess at $file line $line\n"; | 
| 180 |  |  |  |  |  |  | } | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | sub die { | 
| 184 | 2 |  |  | 2 | 1 | 18 | CORE::die $_[0]->dieMess; | 
| 185 |  |  |  |  |  |  | } | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  | sub isThrowing { | 
| 188 | 2 | 100 |  | 2 | 1 | 29 | $THROWING || $CATCHING; | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | sub throw (@) { | 
| 192 | 54 |  |  | 54 | 1 | 161 | my ( $self, @args ) = @_; | 
| 193 |  |  |  |  |  |  | # throw; | 
| 194 | 54 | 100 |  |  |  | 111 | unless (@_) { | 
| 195 | 6 | 50 | 66 |  |  | 19 | unless ( $CATCHING || $THROWING ) { | 
| 196 | 0 |  |  |  |  | 0 | $THROWING = 0; | 
| 197 | 0 |  |  |  |  | 0 | my ( $pack, $file, $line ) = caller; | 
| 198 | 0 |  |  |  |  | 0 | CORE::die "Rethrow without an active exception at $file line $line\n"; | 
| 199 |  |  |  |  |  |  | } | 
| 200 | 6 |  |  |  |  | 21 | $EXCEPTION->throw(@ARGS);      ## To get correct inheritance | 
| 201 |  |  |  |  |  |  | } | 
| 202 | 48 | 100 |  |  |  | 111 | $self = make($self) unless ref $self; | 
| 203 |  |  |  |  |  |  | ### Check here that it is an exception? or in make? | 
| 204 |  |  |  |  |  |  | # Is in a try block | 
| 205 | 48 | 100 |  |  |  | 101 | if ( @STACK ) { | 
| 206 | 44 |  |  |  |  | 43 | $EXCEPTION = $self; | 
| 207 | 44 |  |  |  |  | 69 | @ARGS = @args; | 
| 208 | 44 |  |  |  |  | 203 | local $SIG{'__DIE__'} = 'IGNORE'; | 
| 209 | 44 |  |  |  |  | 56 | $THROWING = 1; | 
| 210 | 44 |  |  |  |  | 46 | $dTHROWING = 1; | 
| 211 | 44 |  |  |  |  | 395 | CORE::die; ## Maybe $self->die(@args) so Warning does not throw? | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  | # Thrown to the wolves | 
| 214 |  |  |  |  |  |  | else { | 
| 215 | 4 |  |  |  |  | 30 | $self->die(@args); | 
| 216 |  |  |  |  |  |  | } | 
| 217 |  |  |  |  |  |  | } | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | ## We 'my' some functions to make them unchangeable from the outside | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | my $findException = sub { | 
| 222 |  |  |  |  |  |  | my($class,$excs) = @_; | 
| 223 |  |  |  |  |  |  | if ($class eq 'Exception::Class::TCF') { | 
| 224 |  |  |  |  |  |  | return grep($_ eq 'Default', @$excs) ? 'Default' : ""; | 
| 225 |  |  |  |  |  |  | } | 
| 226 |  |  |  |  |  |  | my $fclass =  $class; | 
| 227 |  |  |  |  |  |  | $class =~ s/^Exception::Class::TCF:://o; | 
| 228 |  |  |  |  |  |  | return $class if $class eq 'Die' && !$HANDLE_DIE; | 
| 229 |  |  |  |  |  |  | foreach (@$excs) { | 
| 230 |  |  |  |  |  |  | return $_ if &isBelow($fclass,$_); | 
| 231 |  |  |  |  |  |  | } | 
| 232 |  |  |  |  |  |  | ""; | 
| 233 |  |  |  |  |  |  | }; | 
| 234 |  |  |  |  |  |  |  | 
| 235 |  |  |  |  |  |  | my $popFrame = sub { | 
| 236 |  |  |  |  |  |  | ($EXCEPTION,$CATCHING,$THROWING,@ARGS) = @{pop @STACK}; | 
| 237 |  |  |  |  |  |  | }; | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | my $pushFrame = sub { | 
| 240 |  |  |  |  |  |  | push @STACK,[$EXCEPTION,$CATCHING,$THROWING,@ARGS]; | 
| 241 |  |  |  |  |  |  | $CATCHING =  $THROWING = 0; | 
| 242 |  |  |  |  |  |  | undef @ARGS; | 
| 243 |  |  |  |  |  |  | undef $EXCEPTION; | 
| 244 |  |  |  |  |  |  | }; | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | package Exception::Class::TCF::Warning; | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | package Exception::Class::TCF; | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | sub try (&@) { | 
| 251 | 46 |  |  | 46 | 1 | 251 | my($block,@catches) = @_; | 
| 252 | 46 |  |  |  |  | 45 | my($exc,@args,$res); | 
| 253 | 46 |  |  |  |  | 77 | &$pushFrame; | 
| 254 |  |  |  |  |  |  | $HANDLE_WARN && | 
| 255 | 46 | 50 |  | 0 |  | 90 | local ( $SIG{'__WARN__'} =  sub { throw Exception::Class::TCF::Warning @_;  } ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 256 | 46 |  |  |  |  | 47 | $dTHROWING = 0; | 
| 257 | 46 |  |  |  |  | 66 | $res = eval { &$block() }; | 
|  | 46 |  |  |  |  | 104 |  | 
| 258 | 46 |  |  |  |  | 259 | $exc = $EXCEPTION; | 
| 259 | 46 |  |  |  |  | 126 | @args = @ARGS; | 
| 260 | 46 | 100 |  |  |  | 116 | if ($@) { | 
| 261 | 40 |  |  |  |  | 42 | my($action,$type,%excs,@excs,$finalAction); | 
| 262 | 40 |  |  |  |  | 126 | while (($type,$action) = splice @catches,0,2) { | 
| 263 | 47 | 50 |  |  |  | 171 | unless (ref $action eq 'CODE') { | 
| 264 | 0 |  |  |  |  | 0 | my($pack,$file,$line) = caller; | 
| 265 | 0 |  |  |  |  | 0 | warn "Handler for exception key $type is not a function ", | 
| 266 |  |  |  |  |  |  | "reference at $file line $line\n"; | 
| 267 | 0 |  |  |  |  | 0 | next; | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  |  | 
| 270 | 47 |  |  |  |  | 52 | $type =~ s/^Exception::Class::TCF:://o; | 
| 271 | 47 | 100 |  |  |  | 96 | $type = 'Exception::Class::TCF' if $type eq 'Default'; | 
| 272 | 47 | 100 |  |  |  | 82 | if ($type eq 'Finally') { | 
| 273 | 1 | 50 |  |  |  | 5 | $finalAction = $action if ref $action eq 'CODE'; | 
| 274 | 1 |  |  |  |  | 4 | next; | 
| 275 |  |  |  |  |  |  | } | 
| 276 | 46 |  |  |  |  | 81 | $excs{$type} = $action; | 
| 277 | 46 |  |  |  |  | 146 | push @excs,$type; | 
| 278 |  |  |  |  |  |  | } | 
| 279 | 40 |  |  |  |  | 59 | my $catchDie = exists $excs{'Die'}; | 
| 280 |  |  |  |  |  |  | # A 'die', not a 'throw' | 
| 281 | 40 | 100 |  |  |  | 82 | unless ($dTHROWING) { | 
| 282 | 4 | 100 | 66 |  |  | 20 | if ($catchDie || $HANDLE_DIE) { | 
| 283 | 1 |  |  |  |  | 3 | $exc = new Exception::Class::TCF::Die; | 
| 284 | 1 |  |  |  |  | 3 | @args = ($@); | 
| 285 |  |  |  |  |  |  | } | 
| 286 |  |  |  |  |  |  | else { | 
| 287 | 3 |  |  |  |  | 5 | &$popFrame(); | 
| 288 | 3 |  |  |  |  | 14 | CORE::die $@; | 
| 289 |  |  |  |  |  |  | } | 
| 290 |  |  |  |  |  |  | } | 
| 291 | 37 |  |  |  |  | 40 | $dTHROWING = 0; | 
| 292 | 37 | 50 |  |  |  | 74 | my $class = ref($exc) ? ref($exc) : $exc; | 
| 293 | 37 |  |  |  |  | 73 | my $raisedType = &$findException($class,\@excs); | 
| 294 | 37 | 100 |  |  |  | 117 | unless (exists $excs{$raisedType}) { | 
| 295 | 4 |  |  |  |  | 7 | &$popFrame; | 
| 296 | 4 | 50 |  |  |  | 11 | &$finalAction() if defined $finalAction; | 
| 297 | 4 |  |  |  |  | 21 | return $exc->throw(@args); | 
| 298 |  |  |  |  |  |  | } | 
| 299 | 33 |  |  |  |  | 41 | $CATCHING = 1; | 
| 300 | 33 |  |  |  |  | 46 | $res =  eval { &{$excs{$raisedType}}($exc,@args) }; | 
|  | 33 |  |  |  |  | 35 |  | 
|  | 33 |  |  |  |  | 104 |  | 
| 301 | 33 |  |  |  |  | 176 | $CATCHING = 0; | 
| 302 | 33 |  |  |  |  | 40 | $exc = $EXCEPTION; | 
| 303 | 33 |  |  |  |  | 70 | @args = @ARGS; | 
| 304 | 33 |  |  |  |  | 72 | &$popFrame(); | 
| 305 | 33 | 100 |  |  |  | 93 | &$finalAction() if defined $finalAction; | 
| 306 | 33 | 100 |  |  |  | 71 | return $exc->throw(@args) if $dTHROWING; | 
| 307 | 26 | 100 |  |  |  | 45 | CORE::die $@ if $@; | 
| 308 | 25 |  |  |  |  | 471 | return $res; | 
| 309 |  |  |  |  |  |  | } | 
| 310 | 6 |  |  |  |  | 11 | &$popFrame(); | 
| 311 | 6 |  |  |  |  | 23 | my(%catches) = @catches; | 
| 312 | 6 | 100 |  |  |  | 19 | &{$catches{'Finally'}}() if ref $catches{'Finally'} eq 'CODE'; | 
|  | 2 |  |  |  |  | 6 |  | 
| 313 | 6 |  |  |  |  | 24 | $res; | 
| 314 |  |  |  |  |  |  | } | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | sub catch (@) { | 
| 317 | 42 |  |  | 42 | 1 | 603 | return @_; | 
| 318 |  |  |  |  |  |  | } | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | sub finally (&) { | 
| 321 | 2 |  |  | 2 | 1 | 7 | return ('Finally',$_[0]); | 
| 322 |  |  |  |  |  |  | } | 
| 323 |  |  |  |  |  |  |  | 
| 324 |  |  |  |  |  |  | package Exception::Class::TCF::Die; | 
| 325 | 1 |  |  | 1 |  | 10 | use vars '@ISA'; | 
|  | 1 |  |  |  |  | 14 |  | 
|  | 1 |  |  |  |  | 495 |  | 
| 326 |  |  |  |  |  |  | @ISA = qw(Exception::Class::TCF::Error); | 
| 327 |  |  |  |  |  |  |  | 
| 328 |  |  |  |  |  |  | package Exception::Class::TCF::Error; | 
| 329 | 1 |  |  | 1 |  | 21 | use vars '@ISA'; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 357 |  | 
| 330 |  |  |  |  |  |  | @ISA = qw(Exception::Class::TCF); | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | sub die { | 
| 333 | 2 |  |  | 2 |  | 11 | die $_[0]->dieMess; | 
| 334 |  |  |  |  |  |  | } | 
| 335 |  |  |  |  |  |  |  | 
| 336 |  |  |  |  |  |  | package Exception::Class::TCF::Warning; | 
| 337 | 1 |  |  | 1 |  | 7 | use vars '@ISA'; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 193 |  | 
| 338 |  |  |  |  |  |  | @ISA = qw(Exception::Class::TCF); | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | sub die { | 
| 341 | 0 |  |  | 0 |  |  | warn $_[0]->dieMess; | 
| 342 |  |  |  |  |  |  | } | 
| 343 |  |  |  |  |  |  |  | 
| 344 |  |  |  |  |  |  | 1; | 
| 345 |  |  |  |  |  |  |  | 
| 346 |  |  |  |  |  |  | __DATA__ |