sub try (&@) { my($try,$catch) = @_; eval { &$try }; if ($@) { local $_ = $@; &$catch; } } sub catch (&) { $_[0] } try { die "phooey"; } catch { /phooey/ and print "unphooey\n"; }; #### package Exception; use strict; our ($try, $catch, $prior_catch); BEGIN { use Exporter; our ($VERSION, @ISA, @EXPORT); $VERSION = "0.04.5"; @ISA = qw(Exporter); @EXPORT = qw(&try &catch); *CORE::GLOBAL::die = \¨ # this really should probably be done another # way or at least be optional. } sub die { my $catch_sub = $catch; local $catch = $prior_catch; local $_ = shift; chomp; (defined($catch_sub) && $catch_sub ne "" && &$catch_sub) || CORE::die $_; } sub catch (&) { } sub try (&@) { local $prior_catch = $catch; { local ($try, $catch) = @_; eval { &$try; } } &die($@) if $@; } return 1; #### #!/usr/bin/perl use strict; use Exception; sub throw { my $err = shift; print "throwing $err\n"; die $err; } catch { die "You shouldn't see this.\n"; }; # This would simply be insane try { throw "foo"; try { throw "bar"; throw "baz"; print "You should NOT see this line, baz was fatal to this block.\n"; } catch { /^bar/ and do { print "$_ caught and trapped\n"; return 1; # one means exception is "trapped". # unlike using eval, the execution continues # in the block that threw the exception }; /^baz/ and do { print "$_ caught, but we won't trap it here\n"; return 0; # zero means "untrapped". Even though we # can do some processing here, we'll propagate # the exception "outward" }; }; throw "quux"; print "The outer try block completed successfully\n"; } catch { /^foo/ and do { print "$_ caught\n"; return 1; }; /^baz/ and do { print "Caught $_ in outer catch, we'll trap it now\n"; return 1; }; /^quux/ and do { print "$_ caught\n"; try { throw "quuux within quux's catch!"; } catch { /^quuux/ and do { print "$_ caught.\n"; return 1; }; }; return 1; }; }; print "\n"; print "Done testing logic!\n";