cl: Phase 3 complete — *debugger-hook*, *break-on-signals*, invoke-restart-interactively (147 tests)
cl-debugger-hook: mutable global (fn (c hook) result); cl-invoke-debugger calls it with infinite-recursion guard (sets hook nil during call). cl-error now routes unhandled errors through cl-invoke-debugger instead of bare host error — allows the hook to invoke a restart and resume. cl-break-on-signals: when set to a type name, cl-signal fires the debugger hook before walking handlers if the condition matches. cl-invoke-restart-interactively: calls the restart fn with no args (no terminal protocol — equivalent to (invoke-restart name)). 4 new tests in conditions.sx covering all three; Phase 3 fully complete. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -495,6 +495,47 @@
|
||||
(n)
|
||||
(set! cl-restart-stack (slice cl-restart-stack n (len cl-restart-stack)))))
|
||||
|
||||
;; ── *debugger-hook* + invoke-debugger ────────────────────────────────────
|
||||
;;
|
||||
;; cl-debugger-hook: called when an error propagates with no handler.
|
||||
;; Signature: (fn (condition hook) result). The hook arg is itself
|
||||
;; (so the hook can rebind it to nil to prevent recursion).
|
||||
;; nil = use default (re-raise as host error).
|
||||
|
||||
(define cl-debugger-hook nil)
|
||||
|
||||
(define cl-invoke-debugger
|
||||
(fn (c)
|
||||
(if (nil? cl-debugger-hook)
|
||||
(error (str "Debugger: " (cl-condition-message c)))
|
||||
(let ((hook cl-debugger-hook))
|
||||
(set! cl-debugger-hook nil)
|
||||
(let ((result (hook c hook)))
|
||||
(set! cl-debugger-hook hook)
|
||||
result)))))
|
||||
|
||||
;; ── *break-on-signals* ────────────────────────────────────────────────────
|
||||
;;
|
||||
;; When set to a type name string, cl-signal invokes the debugger hook
|
||||
;; before walking handlers if the condition is of that type.
|
||||
;; nil = disabled (ANSI default).
|
||||
|
||||
(define cl-break-on-signals nil)
|
||||
|
||||
;; ── invoke-restart-interactively ──────────────────────────────────────────
|
||||
;;
|
||||
;; Like invoke-restart but calls the restart's fn with no arguments
|
||||
;; (real CL would prompt the user for each arg via :interactive).
|
||||
|
||||
(define cl-invoke-restart-interactively
|
||||
(fn (name)
|
||||
(let ((entry (cl-find-restart-entry name cl-restart-stack)))
|
||||
(if (nil? entry)
|
||||
(error (str "No active restart: " name))
|
||||
(let ((restart-fn (get entry "fn"))
|
||||
(escape (get entry "escape")))
|
||||
(escape (restart-fn)))))))
|
||||
|
||||
;; ── cl-signal (non-unwinding) ─────────────────────────────────────────────
|
||||
;;
|
||||
;; Walks cl-handler-stack; for each matching entry, calls the handler fn.
|
||||
@@ -514,12 +555,16 @@
|
||||
(begin ((get entry "fn") obj) (cl-signal-obj obj (rest stack)))
|
||||
(cl-signal-obj obj (rest stack)))))))
|
||||
|
||||
(define
|
||||
cl-signal
|
||||
(fn
|
||||
(c)
|
||||
(let
|
||||
((obj (if (cl-condition? c) c (cl-make-condition "simple-condition" "format-control" (str c)))))
|
||||
(define cl-signal
|
||||
(fn (c)
|
||||
(let ((obj (if (cl-condition? c)
|
||||
c
|
||||
(cl-make-condition "simple-condition"
|
||||
"format-control" (str c)))))
|
||||
;; *break-on-signals*: invoke debugger hook when type matches
|
||||
(when (and (not (nil? cl-break-on-signals))
|
||||
(cl-condition-of-type? obj cl-break-on-signals))
|
||||
(cl-invoke-debugger obj))
|
||||
(cl-signal-obj obj cl-handler-stack))))
|
||||
|
||||
;; ── cl-error ───────────────────────────────────────────────────────────────
|
||||
@@ -533,7 +578,7 @@
|
||||
(let
|
||||
((obj (cond ((cl-condition? c) c) ((string? c) (cl-make-condition "simple-error" "format-control" c "format-arguments" args)) (:else (cl-make-condition "simple-error" "format-control" (str c))))))
|
||||
(cl-signal-obj obj cl-handler-stack)
|
||||
(error (str "Unhandled CL error: " (cl-condition-message obj))))))
|
||||
(cl-invoke-debugger obj))))
|
||||
|
||||
;; ── cl-warn ────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -660,12 +705,20 @@
|
||||
;; Signals a continuable error. The "continue" restart is established;
|
||||
;; invoke-restart "continue" to proceed past the error.
|
||||
|
||||
(define
|
||||
cl-cerror
|
||||
(fn
|
||||
(continue-string c &rest args)
|
||||
(let
|
||||
((obj (if (cl-condition? c) c (cl-make-condition "simple-error" "format-control" (str c) "format-arguments" args))))
|
||||
|
||||
|
||||
;; ── cl-cerror ──────────────────────────────────────────────────────────────
|
||||
;;
|
||||
;; Signals a continuable error. The "continue" restart is established;
|
||||
;; invoke-restart "continue" to proceed past the error.
|
||||
|
||||
(define cl-cerror
|
||||
(fn (continue-string c &rest args)
|
||||
(let ((obj (if (cl-condition? c)
|
||||
c
|
||||
(cl-make-condition "simple-error"
|
||||
"format-control" (str c)
|
||||
"format-arguments" args))))
|
||||
(cl-restart-case
|
||||
(fn () (cl-signal-obj obj cl-handler-stack))
|
||||
(list "continue" (list) (fn () nil))))))
|
||||
Reference in New Issue
Block a user