Skip to content

Commit e7f71ca

Browse files
committed
Support break-on-error
1 parent 6b0dc29 commit e7f71ca

File tree

4 files changed

+26
-2
lines changed

4 files changed

+26
-2
lines changed

src/JuliaInterpreter.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ isless(x::JuliaProgramCounter, y::Integer) = isless(x.next_stmt, y)
4141

4242
Base.show(io::IO, pc::JuliaProgramCounter) = print(io, "JuliaProgramCounter(", pc.next_stmt, ')')
4343

44+
# Breakpoint support
4445
truecondition(frame) = true
4546
falsecondition(frame) = false
47+
const break_on_error = Ref(false)
4648

4749
"""
4850
BreakpointState(isactive=true, condition=JuliaInterpreter.truecondition)

src/breakpoints.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@ struct Unassigned end
1414

1515
"""
1616
BreakpointRef(framecode, stmtidx)
17+
BreakpointRef(framecode, stmtidx, err)
1718
1819
A reference to a breakpoint at a particular statement index `stmtidx` in `framecode`.
20+
If the break was due to an error, supply that as well.
1921
"""
2022
struct BreakpointRef
2123
framecode::JuliaFrameCode
2224
stmtidx::Int
25+
err
2326
end
27+
BreakpointRef(framecode, stmtidx) = BreakpointRef(framecode, stmtidx, nothing)
2428

2529
function Base.show(io::IO, bp::BreakpointRef)
2630
lineno = linenumber(bp.framecode, bp.stmtidx)

src/interpret.jl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ function evaluate_call!(stack, frame::JuliaStackFrame, call_expr::Expr, pc; exec
211211
return BreakpointRef(newframe.code, newframe.pc[])
212212
end
213213
ret = exec!(stack, newframe)
214+
isa(ret, BreakpointRef) && return ret
214215
pop!(stack)
215216
push!(junk, newframe) # rather than going through GC, just re-use it
216217
return ret
@@ -454,7 +455,7 @@ function _step_expr!(stack, frame, @nospecialize(node), pc::JuliaProgramCounter,
454455
rhs = @lookup(frame, node)
455456
end
456457
catch err
457-
return handle_err(frame, err)
458+
return handle_err(stack, frame, pc, err)
458459
end
459460
@isdefined(rhs) && isa(rhs, BreakpointRef) && return rhs
460461
if isassign(frame, pc)
@@ -484,7 +485,12 @@ function step_expr!(stack, frame, istoplevel::Bool=false)
484485
frame.pc[] = pc
485486
end
486487

487-
function handle_err(frame, err)
488+
function handle_err(stack, frame, pc, err)
489+
if break_on_error[]
490+
frame.pc[] = pc
491+
push!(stack, frame)
492+
return BreakpointRef(frame.code, pc, err)
493+
end
488494
# Check for world age errors, which generally indicate a failure to go back to toplevel
489495
if isa(err, MethodError)
490496
is_arg_types = isa(err.args, DataType)

test/breakpoints.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,16 @@ end
6565
bp = JuliaInterpreter.next_line!(stack, frame)
6666
@test isa(bp, Breakpoints.BreakpointRef)
6767
@test JuliaInterpreter.finish_stack!(stack) == 2
68+
69+
# break on error
70+
inner(x) = error("oops")
71+
outer() = inner(1)
72+
JuliaInterpreter.break_on_error[] = true
73+
stack = JuliaStackFrame[]
74+
frame = JuliaInterpreter.enter_call(outer)
75+
bp = JuliaInterpreter.finish_and_return!(stack, frame)
76+
@test bp.err == ErrorException("oops")
77+
@test length(stack) >= 2
78+
@test stack[1].code.scope.name == :outer
79+
@test stack[2].code.scope.name == :inner
6880
end

0 commit comments

Comments
 (0)