DB-Hooks
view release on metacpan or search on metacpan
lib/DB/Hooks.pm view on Meta::CPAN
}
# We may check if (caller)[3] eq 'import' to distinguish CT and RT
$^P &= ~0x20 if $DB::options{ NonStop };
DB::state( 'single', 1 ) if $DB::options{ Stop }; # IT: commit:1191c38
}
sub _leave {
my $class = shift;
# Now debugger and all required modules are loaded (except Descendant).
# We should inspect %DB::options and setup corresponding perl debugger
# *internal* values
# When <DEBUGGER>::import returns the next OP will be first OP from main::
# We are leaving debugger
my $handler; $handler = DB::on( return => sub{
#TODO? Should be call this from 'postpone'?
return unless $_[0] eq $class .'::import';
DB::unsubscribe( return => $handler );
$DB::after_dbcall = sub{
my $dbg = DB::new; # Create RT debugger
$DB::instance++;
# NOTICE: Circular reference is here.
# The debugger instance exists until main script is terminated
DB::state( debugger => $dbg ); # Make debugger instance accessable via state
#TODO? Probably we want apply options as soon as possible, but keep an eye to
# DB::instance, because we may apply them to a wrong instance.
apply_options();
# TODO: Because RT and CT options are differ on command line
# We may leave CT debugger alive for history reasons
# Delete CT debugger
push @DB::state, shift @DB::state; # Swap RT and CT debuggers
DB::state( debugger => undef );
$DB::instance--;
no strict 'refs'; no warnings 'redefine';
*{ "DB::on" } = \&{ "DB::RT_on" };
*{ "DB::unsubscribe" } = \&{ "DB::RT_unsubscribe" };
DB::say DB::c_( "RT debugger initialized:" , '1;32' ), DB::dumper \@DB::state
if DB::state( 'ddd' ) &16;
};
return;
});
}
## Evaluation in usercontext
# We put code here to execute it only once
my $usercontext; BEGIN {
($usercontext = <<'CODE') =~ s#^\t##gm;
BEGIN {
( $^H, ${^WARNING_BITS}, my $hr ) = @{ DB::state( 'context' )->[0] }[8..10];
%^H = %$hr if $hr;
}
# $@ is cleared when compiller enters *eval* or *BEGIN* block
$@ = (DB::state( 'context' ))[2];
CODE
}
sub eval {
my $expr = shift // return;
DB::state( last_eval => $expr );
my $ctx = DB::state( 'context' );
my $pkg = $ctx->[0][0];
# Read BEWARE at DebugHooks.pod about localization of globals
local $^D;
local $_ = $ctx->[3];
local @_ = @{ $ctx->[1] };
# TODO: Beware that using eval neither silences Perl from printing warnings to STDERR,
# nor does it stuff the text of warning messages into $@
# How to reproduce: $expr = '234asd';
eval "$usercontext; package $pkg;\n$expr";
#NOTICE: perl implicitly add semicolon at the end of expression
#HOWTO reproduce. Run command: X::X;1+2
#
# print $DB::OUT "Error occur while evaluating: $@" if $@
# But if we do this we return wrong value
}
# In theory &save_context should be called as soon, as possible.
sub save_context {
# TODO: What to save:
# https://metacpan.org/source/OPI/Perl-AtEndOfScope-0.03/lib/Perl/AtEndOfScope.pm
# also see perl5db.pl
# TODO: Debugger destroyes $1, $2 etc variables in scope
my $ctx = [ [caller 1], \@_, $@, $_ ]; # The benefit of this is access to stored global values
DB::say '', "Context is stored for $DB::_fix_caller" if DB::state( 'ddd' ) &64;
# Replace __ANON__[lib/DB/Hooks.pm:-2] with target sub
$ctx->[0][3] = $DB::_fix_caller if $DB::_fix_caller;
$ctx->[0][1] =~ s/$DB::options{ pwd }/~/;
return $ctx;
}
# WORKAROUND: &restore_context is called outside of DB::DB, so we should stop debugging it
# to prevent $file:$line updated in unexpected way
# mutate_sub_is_debuggable( \&restore_context, 0 );
sub restore_context {
my $ctx = shift;
# $_ is implicitly localized at &emit by 'for'
# But we still beware about it in &DB::interact if you change it there
# then it will broke the user's context. TODO: IT
( $@ ) = @$ctx[ 2 ];
DB::say 'Context is restored' if DB::state( 'ddd' ) &64;
}
( run in 2.376 seconds using v1.01-cache-2.11-cpan-9e1a9122474 )