diff --git a/src/ASTInterpreter2.jl b/src/ASTInterpreter2.jl index 3ac5b8b13a2c02..e71618801acde3 100644 --- a/src/ASTInterpreter2.jl +++ b/src/ASTInterpreter2.jl @@ -186,10 +186,12 @@ function DebuggerFramework.print_next_state(io::IO, state, frame::JuliaStackFram if isexpr(expr, :call) || isexpr(expr, :return) expr.args = map(var->lookup_var_if_var(frame, var), expr.args) end - for (i, arg) in enumerate(expr.args) - nbytes = length(repr(arg)) - if nbytes > max(40, div(200, length(expr.args))) - expr.args[i] = Suppressed("$nbytes bytes of output") + if isa(expr, Expr) + for (i, arg) in enumerate(expr.args) + nbytes = length(repr(arg)) + if nbytes > max(40, div(200, length(expr.args))) + expr.args[i] = Suppressed("$nbytes bytes of output") + end end end print(io, expr) diff --git a/src/commands.jl b/src/commands.jl index 2fa76e226d5d9e..373ab8ffa2b2da 100644 --- a/src/commands.jl +++ b/src/commands.jl @@ -25,10 +25,33 @@ function perform_return!(state) end end +function propagate_exception!(state, exc) + while !isempty(state.stack) + shift!(state.stack) + if isa(state.stack[1], JuliaStackFrame) + if !isempty(state.stack[1].exception_frames) + # Exception caught + state.stack[1] = JuliaStackFrame(state.stack[1], + JuliaProgramCounter(state.stack[1].exception_frames[end])) + state.stack[1].last_exception[] = exc + return true + end + end + end + rethrow(exc) +end + function DebuggerFramework.execute_command(state, frame::JuliaStackFrame, ::Union{Val{:nc},Val{:n},Val{:se}}, command) - if (pc = command == "nc" ? next_call!(frame) : - command == "n" ? next_line!(frame, state.stack) : - #= command == "se" =# step_expr(frame)) != nothing + pc = try + command == "nc" ? next_call!(frame) : + command == "n" ? next_line!(frame, state.stack) : + #= command == "se" =# step_expr(frame) + catch err + propagate_exception!(state, err) + state.stack[1] = JuliaStackFrame(frame, next_call!(frame, pc)) + return true + end + if pc != nothing state.stack[1] = JuliaStackFrame(state.stack[1], pc) return true end @@ -76,7 +99,13 @@ function DebuggerFramework.execute_command(state, frame::JuliaStackFrame, cmd::U end first = false command == "si" && break - new_pc = _step_expr(frame, pc) + new_pc = try + _step_expr(frame, pc) + catch err + propagate_exception!(state, err) + state.stack[1] = JuliaStackFrame(frame, next_call!(frame, pc)) + return true + end if new_pc == nothing state.stack[1] = JuliaStackFrame(frame, pc) perform_return!(state) diff --git a/test/stepping.jl b/test/stepping.jl index b3a8b5ac07df5e..79ae5583353157 100644 --- a/test/stepping.jl +++ b/test/stepping.jl @@ -131,6 +131,28 @@ execute_command(state, state.stack[1], Val{:n}(), "n") stack = @make_stack g_exc() state = dummy_state(stack) +execute_command(state, state.stack[1], Val{:n}(), "n") +execute_command(state, state.stack[1], Val{:n}(), "n") +@assert isempty(state.stack) +@assert state.overall_result isa ErrorException + +# Test throwing exception across frames +function f_exc_inner() + error() +end + +function f_exc_outer() + try + f_exc_inner() + catch err + return err + end +end + +stack = @make_stack f_exc_outer() +state = dummy_state(stack) + +execute_command(state, state.stack[1], Val{:n}(), "s") execute_command(state, state.stack[1], Val{:n}(), "n") execute_command(state, state.stack[1], Val{:n}(), "n") @assert isempty(state.stack)