Fix up debug/step and janet_step.

Also allow debugging on all signals, including errors.
This is gated behind (setdyn :debug true) in the repl.
This commit is contained in:
Calvin Rose 2019-11-25 20:00:13 -06:00
parent a0a980e0ef
commit 7df0ec6aed
3 changed files with 42 additions and 29 deletions

View File

@ -6,3 +6,6 @@
(for i 0 10 (print i)))
(debug/fbreak myfn 3)
# Enable debugging in repl with
# (setdyn :debug true)

View File

@ -1751,6 +1751,7 @@
(defn eval1 [source]
(def source (if expand (expand source) source))
(var good true)
(var resumeval nil)
(def f
(fiber/new
(fn []
@ -1769,8 +1770,8 @@
(fiber/setenv f env)
(while (let [fs (fiber/status f)]
(and (not= :dead fs) (not= :error fs)))
(def res (resume f nil))
(when good (when going (onstatus f res)))))
(def res (resume f resumeval))
(when good (when going (set resumeval (onstatus f res))))))
# Loop
(def buf @"")
@ -2065,7 +2066,7 @@
"Run a repl. The first parameter is an optional function to call to
get a chunk of source code that should return nil for end of file.
The second parameter is a function that is called when a signal is
caught. Lastly, one can provide an optional environment table to run
caught. One can provide an optional environment table to run
the repl in."
[&opt chunks onsignal env]
(default env (make-env))
@ -2076,32 +2077,34 @@
buf)))
(defn make-onsignal
[e level]
(fn [f x]
(case (fiber/status f)
:dead (do
(pp x)
(put e '_ @{:value x}))
:debug (let [nextenv (make-env env)]
(put nextenv :fiber f)
(put nextenv :debug-level level)
(debug/stacktrace f x)
(defn debugger-chunks [buf p]
(def status (parser/state p :delimiters))
(def c ((parser/where p) 0))
(def prompt (string "debug[" level "]:" c ":" status "> "))
(getline prompt buf))
(repl debugger-chunks (make-onsignal nextenv (+ 1 level)) nextenv)
(print "exiting debug[" level "]")
(def lastval (get-in nextenv ['_ :value] (nextenv :resume-value)))
(pp lastval)
(put e '_ @{:value lastval}))
(debug/stacktrace f x))))
(default onsignal (make-onsignal env 1))
(defn enter-debugger
[f x]
(def nextenv (make-env env))
(put nextenv :fiber f)
(put nextenv :debug-level level)
(put nextenv :signal x)
(debug/stacktrace f x)
(defn debugger-chunks [buf p]
(def status (parser/state p :delimiters))
(def c ((parser/where p) 0))
(def prompt (string "debug[" level "]:" c ":" status "> "))
(getline prompt buf))
(print "entering debug[" level "] - (quit) to exit")
(repl debugger-chunks (make-onsignal nextenv (+ 1 level)) nextenv)
(print "exiting debug[" level "]")
(nextenv :resume-value))
(fn [f x]
(if (= :dead (fiber/status f))
(do (pp x) (put e '_ @{:value x}))
(if (e :debug)
(enter-debugger f x)
(do (debug/stacktrace f x) nil)))))
(run-context {:env env
:chunks chunks
:on-status onsignal
:on-status (or onsignal (make-onsignal env 1))
:source "repl"}))
# Clean up some extra defs

View File

@ -1010,8 +1010,16 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status)
* reseting breakpoints to how they were prior. Yes, it's a bit hacky.
*/
JanetSignal janet_step(JanetFiber *fiber, Janet in, Janet *out) {
Janet *stack = fiber->data + fiber->frame;
uint32_t *pc = janet_stack_frame(stack)->pc;
/* No finished or currently alive fibers. */
JanetFiberStatus status = janet_fiber_status(fiber);
if (status == JANET_STATUS_ALIVE ||
status == JANET_STATUS_DEAD ||
status == JANET_STATUS_ERROR) {
janet_panicf("cannot step fiber with status :%s", janet_status_names[status]);
}
/* Get PC for setting breakpoints */
uint32_t *pc = janet_stack_frame(fiber->data + fiber->frame)->pc;
/* Check current opcode (sans debug flag). This tells us where the next or next two candidate
* instructions will be. Usually it's the next instruction in memory,
@ -1049,13 +1057,12 @@ JanetSignal janet_step(JanetFiber *fiber, Janet in, Janet *out) {
}
/* Go */
JanetSignal signal = run_vm(fiber, in, janet_fiber_status(fiber));
JanetSignal signal = janet_continue(fiber, in, out);
/* Restore */
if (nexta) *nexta = olda;
if (nextb) *nextb = oldb;
*out = *janet_vm_return_reg;
return signal;
}