# -*- coding: utf-8 -*- # Copyright (C) 2011-2012 Rocky Bernstein use warnings; no warnings 'redefine'; use rlib '../../../..'; # require_relative '../../app/condition' package Devel::Trepan::CmdProcessor::Command::Step; use if !@ISA, Devel::Trepan::CmdProcessor::Command ; unless (@ISA) { eval <<'EOE'; use constant ALIASES => qw(s step+ step- s+ s-); use constant CATEGORY => 'running'; use constant SHORT_HELP => 'Step program (possibly entering called functions)'; use constant MIN_ARGS => 0; # Need at least this many use constant MAX_ARGS => undef; # Need at most this many - undef -> unlimited. use constant NEED_STACK => 1; EOE } use strict; use vars qw(@ISA); @ISA = @CMD_ISA; use vars @CMD_VARS; # Value inherited from parent $NAME = set_name(); $HELP = <<'HELP'; =pod step[+|-] [into] [I] step over step out Execute the current line, stopping at the next event. Sometimes this is called "step into". With an integer argument, step that many times. With an 'until' expression that expression is evaluated and we stop the first time it is true. A suffix of C<+> in a command or an alias forces a move to another position, while a suffix of C<-> disables this requirement. A suffix of C> will continue until the next call. (C will run run until the return for that call.) If no suffix is given, the debugger setting C determines this behavior. =head2 Examples: step # step 1 event, any event obeying 'set different' setting step 1 # same as above step+ # same but force stopping on a new line step- # same but force stopping on a new line a new frame added step over # same as 'next' step out # same as 'finish' Related and similar is the C (step over) and C (step out) commands. All of these are slower than running to a breakpoint. See also C. =cut HELP my $Keyword_to_related_cmd = { 'out' => 'finish', 'over' => 'next', 'into' => 'step', }; # include Trepan::Condition # This method runs the command sub run($$) { my ($self, $args) = @_; my $proc = $self->{proc}; my $opts = $proc->parse_next_step_suffix($args->[0]); # condition = nil if (0 == $#$args) { # Form is: "step" which means "step 1" $proc->{skip_count} = 0; } else { my $replace_cmd = $Keyword_to_related_cmd->{$args->[1]}; if (defined($replace_cmd)) { my $cmd = $proc->{commands}{$replace_cmd}; return $cmd->run( ($replace_cmd, splice(@$args, 2)) ); # } elsif ('until' eq $args->[1]) { # my $try_condition = join(@$args[2..-1], ' '); # if (valid_condition?(try_condition)) { # $condition = $try_condition; # $opts-{different_pos} = 0; # $proc->{skip_count} = 0; # } # elsif('to' eq $args[1]) { # if args.size != 3; # $self->errmsg('Expecting a method name after "to"'); # return; # elsif (!@proc.method?(args[2])) { # $self->errmsg("${args[2]} doesn't seem to be a method name"); # return; # } else { # $opts->{to_method{ = $args->[2]; # $opts->{different_pos} = 0; # skip_count = 0 # } # } elsif ('thread' eq $args->[1]) { # $condition = "Thread.current.object_id == ${Thread.current.object_id}" # $opts[:different_pos] = 0; # $proc->{skip_count] = 0; } else { my $count_str = $args->[1]; my $int_opts = { msg_on_error => "The 'step' command argument must eval to an integer. Got: ${count_str}", min_value => 1 }; # }.merge(opts) my $count = $proc->get_an_int($count_str, $int_opts); return unless defined($count); # step 1 is $proc->{skip_count} = 0 or "stop next event" $proc->{skip_count} = $count - 1 ; } } $proc->step($opts) } unless (caller) { # require_relative '../mock' # dbgr, cmd = MockDebugger::setup # p cmd.run([cmd.name]) } 1;