# -*- coding: utf-8 -*- # Copyright (C) 2012 Rocky Bernstein use warnings; use rlib '../../..'; package Devel::Trepan::CmdProcessor; use Devel::Trepan::Util qw(hash_merge uniq_abbrev); use PadWalker qw(peek_my peek_our); use strict; use vars qw($HAVE_EVAL_WITH_LEXICALS); BEGIN { $HAVE_EVAL_WITH_LEXICALS = eval("use Eval::WithLexicals; 1") ? 1 : 0; } my $given_eval_warning = 0; sub eval($$$$$) { my ($self, $code_to_eval, $opts, $correction) = @_; no warnings 'once'; my $return_type = $opts->{return_type}; if (0 == $self->{frame_index} || !$HAVE_EVAL_WITH_LEXICALS) { unless (0 == $self->{frame_index}) { $self->msg("Evaluation occurs in top-most frame not this one"); } $DB::eval_str = $self->{dbgr}->evalcode($code_to_eval); $DB::eval_opts = $opts; $DB::result_opts = $opts; ## This doesn't work because it doesn't pick up "my" variables # DB::eval_with_return($code_to_eval, $opts, @DB::saved); # $self->process_after_eval(); # All the way back to DB seems to work here. $self->{DB_running} = 2; $self->{leave_cmd_loop} = 1; } else { # Have to use Eval::WithLexicals which, unfortunately, # loses on 'local' variables. my $i = 0; while (my ($pkg, $file, $line, $fn) = caller($i++)) { ; }; my $diff = $i - $DB::stack_depth; my $my_hash = peek_my($diff + $self->{frame_index} + $correction); my $our_hash = peek_our($diff + $self->{frame_index} + $correction); my $var_hash = hash_merge($my_hash, $our_hash); unless ($given_eval_warning) { $self->msg("Evaluation in this frame may not find local values"); $given_eval_warning = 0 # 1; } my $context = 'scalar'; $return_type = '$' unless defined($return_type); if ('@' eq $return_type) { $context = 'list'; $code_to_eval = "\@DB::eval_result = $code_to_eval"; } else { ## FIXME do fixup for hash. $context = 'scalar'; $code_to_eval = "\$DB::eval_result = $code_to_eval"; } my $eval = Eval::WithLexicals->new( lexicals => $var_hash, in_package => $self->{frame}{pkg}, context => $context, # prelude => 'use warnings', # default 'use strictures 1' ); $eval->eval($code_to_eval); } if ('@' eq $return_type) { return @DB::eval_result; } else { return $DB::eval_result; } } my $last_eval_value = 0; sub handle_eval_result($) { my ($self) = @_; my $val_str; my $prefix="\$DB::D[$last_eval_value] ="; # Perltidy::Dumper uses Tidy which looks at @ARGV for filenames. # Having a non-empty @ARGV will cause Tidy to croak. local @ARGV=(); my $fn; my $print_properties = {}; my $evdisp = $self->{settings}{displayeval}; if ('tidy' eq $evdisp) { $fn = \&Data::Dumper::Perltidy::Dumper; } elsif ('dprint' eq $evdisp) { $print_properties = { colored => $self->{settings}{highlight}, }; $fn = \&Data::Printer::p; } else { $fn = \&Data::Dumper::Dumper; } my $return_type = $DB::eval_opts->{return_type}; $return_type = '' unless defined $return_type; if ('$' eq $return_type) { if (defined $DB::eval_result) { $DB::D[$last_eval_value++] = $DB::eval_result; if ('dprint' eq $evdisp) { $val_str = $fn->(\$DB::eval_result, %$print_properties); } else { $val_str = $fn->($DB::eval_result); } chomp $val_str; } else { $DB::eval_result = '' ; } $self->msg("$prefix $DB::eval_result"); } elsif ('@' eq $return_type) { if (@DB::eval_result) { $val_str = $fn->(\@DB::eval_result, %$print_properties); chomp $val_str; @{$DB::D[$last_eval_value++]} = @DB::eval_result; } else { $val_str = '' } $self->msg("$prefix\n\@\{$val_str}"); } elsif ('%' eq $return_type) { if (%DB::eval_result) { $val_str = $fn->(\%DB::eval_result, %$print_properties); chomp $val_str; @{$DB::D[$last_eval_value++]} = %DB::eval_result; } else { $val_str = '' } $self->msg("$prefix\n\@\{$val_str}"); } elsif ('>' eq $return_type || '2>' eq $return_type ) { $self->msg($DB::eval_result); } else { if (defined $DB::eval_result) { if ('dprint' eq $evdisp) { $val_str = $DB::D[$last_eval_value++] = $fn->(\$DB::eval_result, %$print_properties); } else { $val_str = $DB::D[$last_eval_value++] = $fn->($DB::eval_result); } chomp $val_str; } else { $val_str = '' } $self->msg("$prefix ${val_str}"); } if (defined($self->{set_wp})) { $self->{set_wp}->old_value($DB::eval_result); $self->{set_wp} = undef; } $DB::eval_opts = { return_type => '', }; $DB::eval_result = undef; @DB::eval_result = undef; } unless (caller) { } scalar "Just one part of the larger Devel::Trepan::CmdProcessor";