Skip to content

Commit 5a6f71b

Browse files
authored
add until_line! to step to next line lower down in source code (#266)
1 parent a652d66 commit 5a6f71b

File tree

3 files changed

+51
-7
lines changed

3 files changed

+51
-7
lines changed

docs/src/dev_reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ JuliaInterpreter.maybe_evaluate_builtin
4646
JuliaInterpreter.next_call!
4747
JuliaInterpreter.maybe_next_call!
4848
JuliaInterpreter.next_line!
49+
JuliaInterpreter.until_line!
4950
JuliaInterpreter.maybe_reset_frame!
5051
JuliaInterpreter.maybe_step_through_wrapper!
5152
JuliaInterpreter.maybe_step_through_kwprep!

src/commands.jl

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,25 @@ function next_line!(@nospecialize(recurse), frame::Frame, istoplevel::Bool=false
180180
end
181181
next_line!(frame::Frame, istoplevel::Bool=false) = next_line!(finish_and_return!, frame, istoplevel)
182182

183+
"""
184+
pc = until_line!(recurse, frame, line=nothing istoplevel=false)
185+
pc = until_line!(frame, line=nothing, istoplevel=false)
186+
187+
Execute until the current frame reaches a line greater than `line`. If `line == nothing`
188+
execute until the current frame reaches any line greater than the current line.
189+
"""
190+
function until_line!(@nospecialize(recurse), frame::Frame, line::Union{Nothing, Integer}=nothing, istoplevel::Bool=false)
191+
pc = frame.pc
192+
initialline, initialfile = linenumber(frame, pc), getfile(frame, pc)
193+
line === nothing && (line = initialline + 1)
194+
predicate(frame) = isexpr(pc_expr(frame), :return) || (linenumber(frame) >= line && getfile(frame) == initialfile)
195+
pc = next_until!(predicate, frame, istoplevel)
196+
(pc === nothing || isa(pc, BreakpointRef)) && return pc
197+
maybe_step_through_kwprep!(recurse, frame, istoplevel)
198+
maybe_next_call!(recurse, frame, istoplevel)
199+
end
200+
until_line!(frame::Frame, line::Union{Nothing, Integer}=nothing, istoplevel::Bool=false) = until_line!(finish_and_return!, frame, line, istoplevel)
201+
183202
"""
184203
cframe = maybe_step_through_wrapper!(recurse, frame)
185204
cframe = maybe_step_through_wrapper!(frame)
@@ -343,13 +362,15 @@ function unwind_exception(frame::Frame, exc)
343362
end
344363

345364
"""
346-
ret = debug_command(recurse, frame, cmd, rootistoplevel=false)
347-
ret = debug_command(frame, cmd, rootistoplevel=false)
365+
ret = debug_command(recurse, frame, cmd, rootistoplevel=false; line=nothing)
366+
ret = debug_command(frame, cmd, rootistoplevel=false; line=nothing)
348367
349-
Perform one "debugger" command. `cmd` should be one of:
368+
Perform one "debugger" command. The keyword arguments are not used for all debug commands.
369+
`cmd` should be one of:
350370
351371
- `:n`: advance to the next line
352372
- `:s`: step into the next call
373+
- `:until`: advance the frame to line `line` if given, otherwise advance to the line after the current line
353374
- `:c`: continue execution until termination or reaching a breakpoint
354375
- `:finish`: finish the current frame and return to the parent
355376
@@ -362,7 +383,7 @@ or one of the 'advanced' commands
362383
363384
`rootistoplevel` and `ret` are as described for [`JuliaInterpreter.maybe_reset_frame!`](@ref).
364385
"""
365-
function debug_command(@nospecialize(recurse), frame::Frame, cmd::Symbol, rootistoplevel::Bool=false)
386+
function debug_command(@nospecialize(recurse), frame::Frame, cmd::Symbol, rootistoplevel::Bool=false; line=nothing)
366387
function nicereturn!(@nospecialize(recurse), frame, pc, rootistoplevel)
367388
if pc === nothing || isa(pc, BreakpointRef)
368389
return maybe_reset_frame!(recurse, frame, pc, rootistoplevel)
@@ -383,6 +404,7 @@ function debug_command(@nospecialize(recurse), frame::Frame, cmd::Symbol, rootis
383404
cmd == :nc && return nicereturn!(recurse, frame, next_call!(recurse, frame, istoplevel), rootistoplevel)
384405
cmd == :n && return maybe_reset_frame!(recurse, frame, next_line!(recurse, frame, istoplevel), rootistoplevel)
385406
cmd == :se && return maybe_reset_frame!(recurse, frame, step_expr!(recurse, frame, istoplevel), rootistoplevel)
407+
cmd == :until && return maybe_reset_frame!(recurse, frame, until_line!(recurse, frame, line, istoplevel), rootistoplevel)
386408

387409
enter_generated = false
388410
if cmd == :sg
@@ -434,5 +456,5 @@ function debug_command(@nospecialize(recurse), frame::Frame, cmd::Symbol, rootis
434456
end
435457
throw(ArgumentError("command $cmd not recognized"))
436458
end
437-
debug_command(frame::Frame, cmd::Symbol, rootistoplevel::Bool=false) =
438-
debug_command(finish_and_return!, frame, cmd, rootistoplevel)
459+
debug_command(frame::Frame, cmd::Symbol, rootistoplevel::Bool=false; kwargs...) =
460+
debug_command(finish_and_return!, frame, cmd, rootistoplevel; kwargs...)

test/debug.jl

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ using JuliaInterpreter, Test
22
using JuliaInterpreter: enter_call, enter_call_expr, get_return, @lookup
33
using Base.Meta: isexpr
44

5-
const ALL_COMMANDS = (:n, :s, :c, :finish, :nc, :se, :si)
5+
const ALL_COMMANDS = (:n, :s, :c, :finish, :nc, :se, :si, :until)
66

77
function step_through_command(fr::Frame, cmd::Symbol)
88
while true
@@ -85,6 +85,27 @@ struct B{T} end
8585
@test step_through(:($(gcd)(10,20))) == gcd(10, 20)
8686
end
8787

88+
@testset "until" begin
89+
function f_with_lines(s)
90+
sin(2.0)
91+
cos(2.0)
92+
for i in 1:100
93+
s += i
94+
end
95+
sin(2.0)
96+
end
97+
meth_def = @__LINE__() - 8
98+
99+
frame = enter_call(f_with_lines, 0)
100+
@test whereis(frame)[2] == meth_def + 1
101+
debug_command(frame, :until)
102+
@test whereis(frame)[2] == meth_def + 2
103+
debug_command(frame, :until; line=(meth_def + 4))
104+
@test whereis(frame)[2] == meth_def + 4
105+
debug_command(frame, :until; line=(meth_def + 6))
106+
@test whereis(frame)[2] == meth_def + 6
107+
end
108+
88109
@testset "generated" begin
89110
frame = enter_call_expr(:($(callgenerated)()))
90111
f, pc = debug_command(frame, :s)

0 commit comments

Comments
 (0)