File Coverage

lib/Devel/Trepan/CmdProcessor/Eval.pm
Criterion Covered Total %
statement 27 118 22.8
branch 1 48 2.0
condition 0 5 0.0
subroutine 9 11 81.8
pod 0 2 0.0
total 37 184 20.1


line stmt bran cond sub pod time code
1             # -*- coding: utf-8 -*-
2             # Copyright (C) 2012-2014 Rocky Bernstein <rocky@cpan.org>
3 12     12   81 use warnings; use utf8;
  12     12   32  
  12         372  
  12         70  
  12         129  
  12         98  
4 12     12   323 use rlib '../../..';
  12         29  
  12         175  
5              
6             package Devel::Trepan::CmdProcessor;
7 12     12   3811 use Devel::Trepan::Util qw(hash_merge uniq_abbrev);
  12         30  
  12         899  
8 12     12   5317 use PadWalker qw(peek_my peek_our);
  12         7425  
  12         821  
9 12     12   89 use strict;
  12         32  
  12         380  
10              
11             # Note DB::Eval uses and sets its own variables.
12              
13 12 50   12   132 use constant HAVE_EVAL_WITH_LEXICALS => eval("use Eval::WithLexicals; 1") ? 1 : 0;
  12     12   30  
  12         683  
  12         5132  
  12         438390  
  12         229  
14              
15             my $given_eval_warning = 0;
16              
17             sub eval($$$$) {
18 0     0 0   my ($self, $code_to_eval, $opts) = @_;
19 12     12   114 no warnings 'once';
  12         32  
  12         12396  
20 0           my $return_type = $opts->{return_type};
21 0 0 0       if (0 == $self->{frame_index} || !HAVE_EVAL_WITH_LEXICALS) {
22 0 0         unless (0 == $self->{frame_index}) {
23 0           $self->msg("Evaluation occurs in top-most frame not this one");
24             }
25 0           $DB::eval_str = $self->{dbgr}->evalcode($code_to_eval);
26 0           $DB::eval_opts = $opts;
27 0           $DB::result_opts = $opts;
28              
29             ## This doesn't work because it doesn't pick up "my" variables
30             # DB::eval_with_return($code_to_eval, $opts, @DB::saved);
31             # $self->process_after_eval();
32              
33             # All the way back to DB seems to work here.
34 0           $self->{DB_running} = 2;
35 0           $self->{leave_cmd_loop} = 1;
36              
37             } else {
38             # Have to use Eval::WithLexicals which, unfortunately,
39             # loses on 'local' variables.
40              
41 0           my $stack_size_with_debugger = 0;
42 0           while (my ($pkg, $file, $line, $fn) =
43             caller($stack_size_with_debugger++)) { ; };
44 0           my $diff = $stack_size_with_debugger - $self->{stack_size};
45              
46 0           my $my_hash = peek_my($diff + $self->{frame_index} - 1);
47 0           my $our_hash = peek_our($diff + $self->{frame_index} - 1);
48 0           my $var_hash = hash_merge($my_hash, $our_hash);
49              
50 0 0         unless ($given_eval_warning) {
51 0           $self->msg("Evaluation in this frame may not find local values");
52 0           $given_eval_warning = 0 # 1;
53             }
54              
55 0           my $context = 'scalar';
56 0 0         $return_type = '$' unless defined($return_type);
57 0 0         if ('@' eq $return_type) {
58 0           $context = 'list';
59 0           $code_to_eval = "\@DB::eval_result = $code_to_eval";
60             } else {
61             ## FIXME do fixup for hash.
62 0           $context = 'scalar';
63 0           $code_to_eval = "\$DB::eval_result = $code_to_eval";
64             }
65             my $eval = Eval::WithLexicals->new(
66             lexicals => $var_hash,
67             in_package => $self->{frame}{pkg},
68 0           context => $context,
69             # prelude => 'use warnings', # default 'use strictures 1'
70             );
71 0           $eval->eval($code_to_eval);
72             }
73 0 0         if ('@' eq $return_type) {
74 0           return @DB::eval_result;
75             } else {
76 0           return $DB::eval_result;
77             }
78             }
79              
80             # FIXME: have a way to customize Data::Dumper, PerlTidy etc.
81             require Data::Dumper;
82             # FIXME: remove this when converted to OO forms of Data::Dumper
83             $Data::Dumper::Terse = 1;
84              
85             my $last_eval_value = 0;
86              
87             sub handle_eval_result($) {
88 0     0 0   my ($self) = @_;
89 0           my $val_str;
90 0           my $prefix="\$DB::D[$last_eval_value] =";
91              
92             # Perltidy::Dumper uses Tidy which looks at @ARGV for filenames.
93             # Having a non-empty @ARGV will cause Tidy to croak.
94 0           local @ARGV=();
95              
96 0           my $fn;
97 0           my $print_properties = {};
98 0           my $evdisp = $self->{settings}{displayeval};
99              
100             # FIXME: switch over entirely to the OO way of using Data::Dumper
101             # than set this global.
102 0           my $old_terse = $Data::Dumper::Terse;
103 0           $Data::Dumper::Terse = 1;
104              
105              
106             # FIXME: this is way ugly. We could probably use closures
107             # (anonymous subroutines) to combine this and the if code below
108 0 0         if ('tidy' eq $evdisp) {
    0          
    0          
109 0           $fn = \&Data::Dumper::Perltidy::Dumper;
110             } elsif ('ddp' eq $evdisp) {
111             $print_properties = {
112             colored => $self->{settings}{highlight},
113 0           };
114 0           $fn = \&Data::Printer::p;
115             } elsif ('concise' eq $evdisp) {
116 0           $fn = \&Data::Dumper::Concise::Dumper;
117             } else {
118 0           $fn = \&Data::Dumper::Dumper;
119             }
120 0           my $return_type = $DB::eval_opts->{return_type};
121 0 0         $return_type = '' unless defined $return_type;
122 0 0 0       if ('$' eq $return_type) {
    0          
    0          
    0          
123 0 0         if (defined $DB::eval_result) {
124 0           $DB::D[$last_eval_value++] = $DB::eval_result;
125 0 0         if ('ddp' eq $evdisp) {
126 0           $val_str =
127             $fn->(\$DB::eval_result, %$print_properties);
128             } else {
129 0           $val_str = $fn->($DB::eval_result);
130             }
131 0           chomp $val_str;
132             } else {
133 0           $DB::eval_result = '<undef>' ;
134             }
135 0           $self->msg("$prefix $DB::eval_result");
136             } elsif ('@' eq $return_type) {
137 0 0         if (@DB::eval_result) {
138 0           $val_str = $fn->(\@DB::eval_result, %$print_properties);
139 0           chomp $val_str;
140 0           @{$DB::D[$last_eval_value++]} = @DB::eval_result;
  0            
141             } else {
142 0           $val_str = '<undef>'
143             }
144 0           $self->msg("$prefix\n\@\{$val_str}");
145             } elsif ('%' eq $return_type) {
146 0 0         if (%DB::eval_result) {
147 0 0         if ('dumper' eq $evdisp) {
    0          
148 0           my $d = Data::Dumper->new([\%DB::eval_result]);
149 0           $d->Terse(1)->Sortkeys(1);
150 0           $val_str = $d->Dump()
151             } elsif ('ddp' eq $evdisp) {
152 0           $val_str = $fn->(\%DB::eval_result, %$print_properties);
153             } else {
154 0           $val_str = $fn->(\%DB::eval_result);
155             }
156 0           chomp $val_str;
157 0           @{$DB::D[$last_eval_value++]} = %DB::eval_result;
  0            
158             } else {
159 0           $val_str = '<undef>'
160             }
161 0           $self->msg("$prefix\n\@\{$val_str}");
162             } elsif ('>' eq $return_type || '2>' eq $return_type ) {
163 0           $self->msg($DB::eval_result);
164             } else {
165 0 0         if (defined $DB::eval_result) {
166 0 0         if ('ddp' eq $evdisp) {
167 0           $val_str = $DB::D[$last_eval_value++] =
168             $fn->(\$DB::eval_result, %$print_properties);
169             } else {
170 0           $val_str = $DB::D[$last_eval_value++] =
171             $fn->($DB::eval_result);
172             }
173 0           chomp $val_str;
174             } else {
175 0           $val_str = '<undef>'
176             }
177 0           $self->msg("$prefix ${val_str}");
178             }
179              
180 0 0         if (defined($self->{set_wp})) {
181 0           $self->{set_wp}->old_value($DB::eval_result);
182 0           $self->{set_wp} = undef;
183             }
184              
185             $DB::eval_opts = {
186 0           return_type => '',
187             };
188 0           $DB::eval_result = undef;
189 0           @DB::eval_result = undef;
190              
191 0           $Data::Dumper::Terse = $old_terse;
192              
193             }
194              
195             unless (caller) {
196             }
197             scalar "Just one part of the larger Devel::Trepan::CmdProcessor";