Developer reference
Capturing arguments
Rebugger.stepin — Function.stepin(s)Given a buffer s representing a string and "point" (the seek position) set at a call expression, replace the contents of the buffer with a let expression that wraps the body of the callee.
For example, if s has contents
<some code>
if x > 0.5
^fcomplex(x)
<more code>where in the above ^ indicates position(s) ("point"), and if the definition of fcomplex is
function fcomplex(x::A, y=1, z=""; kw1=3.2) where A<:AbstractArray{T} where T
<body>
endrewrite s so that its contents are
@eval ModuleOf_fcomplex let (x, y, z, kw1, A, T) = Main.Rebugger.getstored(id)
<body>
endwhere Rebugger.getstored returns has been pre-loaded with the values that would have been set when you called fcomplex(x) in s above. This line can be edited and evaled at the REPL to analyze or improve fcomplex, or can be used for further stepin calls.
Rebugger.prepare_caller_capture! — Function.callexpr = prepare_caller_capture!(io)Given a buffer io representing a string and "point" (the seek position) set at a call expression, replace the call with one that stashes the function and arguments of the call.
For example, if io has contents
<some code>
if x > 0.5
^fcomplex(x, 2; kw1=1.1)
<more code>where in the above ^ indicates position(s) ("point"), rewrite this as
<some code>
if x > 0.5
Main.Rebugger.stashed[] = (fcomplex, (x, 2), (kw1=1.1,))
throw(Rebugger.StopException())
<more code>(Keyword arguments do not affect dispatch and hence are not stashed.) Consequently, if this is evaled and execution reaches "^", it causes the arguments of the call to be placed in Rebugger.stashed.
callexpr is the original (unmodified) expression specifying the call, i.e., fcomplex(x, 2; kw1=1.1) in this case.
This does the buffer-preparation for caller capture. For callee capture, see method_capture_from_callee, and stepin which puts these two together.
Rebugger.method_capture_from_callee — Function.uuid = method_capture_from_callee(method; overwrite::Bool=false)Create a version of method that stores its inputs in Main.Rebugger.stored. For a method
function fcomplex(x::A, y=1, z=""; kw1=3.2) where A<:AbstractArray{T} where T
<body>
endif overwrite=false, this generates a new method
function hidden_fcomplex(x::A, y=1, z=""; kw1=3.2) where A<:AbstractArray{T} where T
Main.Rebugger.stored[uuid] = Main.Rebugger.Stored(fcomplex, (:x, :y, :z, :kw1, :A, :T), deepcopy((x, y, z, kw1, A, T)))
throw(StopException())
end(If a uuid already exists for method from a previous call to method_capture_from_callee, it will simply be returned.)
With overwrite=true, there are two differences:
- it replaces
fcomplexrather than defininghidden_fcomplex - rather than throwing
StopException, it re-inserts<body>after the line performing storage
The returned uuid can be used for accessing the stored data.
Rebugger.signature_names! — Function.fname, argnames, kwnames, parameternames = signature_names!(sigex::Expr)Return the function name fname and names given to its arguments, keyword arguments, and parameters, as specified by the method signature-expression sigex.
sigex will be modified if some of the arguments are unnamed.
Examples
julia> Rebugger.signature_names!(:(complexargs(w::Ref{A}, @nospecialize(x::Integer), y, z::String=""; kwarg::Bool=false, kw2::String="", kwargs...) where A <: AbstractArray{T,N} where {T,N}))
(:complexargs, (:w, :x, :y, :z), (:kwarg, :kw2, :kwargs), (:A, :T, :N))
julia> ex = :(myzero(::Float64)); # unnamed argument
julia> Rebugger.signature_names!(ex)
(:myzero, (:__Float64_1,), (), ())
julia> ex
:(myzero(__Float64_1::Float64))Capturing stacktrace
Rebugger.capture_stacktrace — Function.uuids = capture_stacktrace(mod, command)Execute command in module mod. command must throw an error. Then instrument the methods in the stacktrace so that their input variables are stored in Rebugger.stored. After storing the inputs, restore the original methods.
Since this requires two evals of command, usage should be limited to deterministic expressions that always result in the same call chain.
Rebugger.pregenerated_stacktrace — Function.usrtrace, defs = pregenerated_stacktrace(trace, topname=:capture_stacktrace)Generate a list of methods usrtrace and their corresponding definition-expressions defs from a stacktrace. Not all methods can be looked up, but this attempts to resolve, e.g., keyword-handling methods and so on.
Rebugger.linerange — Function.r = linerange(expr, offset=0)Compute the range of lines occupied by expr. Returns nothing if no line statements can be found.
Utilities
Rebugger.clear — Function.Rebugger.clear()Clear internal data. This deletes storage associated with stored variables, but also forces regeneration of capture methods, which can be handy while debugging Rebugger itself.
Rebugger.getstored — Function.args_and_types = Rebugger.getstored(uuid)Retrieve the values of stored arguments and type-parameters from the store specified uuid. This makes a copy of values, so as to be safe for repeated execution of methods that modify their inputs.