0.9.17.15: silence %SAP-ALIEN compiler-note for MAKE-ALIEN in default policy
[sbcl.git] / src / code / step.lisp
index db86838..9d63d34 100644 (file)
 
 (in-package "SB-IMPL") ; in warm SBCL
 
+(defun step-form (form args)
+  (restart-case
+      (signal 'step-form-condition
+              :form form
+              :args args)
+    (step-continue ()
+      :report "Resume normal execution"
+      (disable-stepping)
+      (setf *step-out* nil))
+    (step-out ()
+      :report "Resume stepping after returning from this function"
+      (ecase *step-out*
+        ((nil)
+         (error "Can't STEP-OUT: No STEP-IN on the call-stack"))
+        ((t :maybe)
+         (disable-stepping)
+         (setf *step-out* t)))
+      nil)
+    (step-next ()
+      :report "Step over call"
+      nil)
+    (step-into ()
+      :report "Step into call"
+      t)))
+
+(defun step-values (form &rest values)
+  (declare (dynamic-extent values))
+  (signal 'step-values-condition :form form :result values)
+  (values-list values))
+
+(defun step-finished ()
+  (restart-case
+      (signal 'step-finished-condition)
+    (continue ())))
+
 (defvar *step-help* "The following commands are available at the single
 stepper's prompt:
 
@@ -22,16 +57,12 @@ stepper's prompt:
  N: Evaluate the current expression without stepping.
  C: Evaluate to finish without stepping.
  Q: Abort evaluation.
+ B: Backtrace.
  ?: Display this message.
 ")
 
 (defgeneric single-step (condition))
 
-(defmethod single-step ((condition step-variable-condition))
-  (format *debug-io* "; ~A => ~S~%"
-          (step-condition-form condition)
-          (step-condition-result condition)))
-
 (defmethod single-step ((condition step-values-condition))
   (let ((values (step-condition-result condition)))
     (format *debug-io* "; ~A => ~:[#<no value>~;~{~S~^, ~}~]~%"
@@ -39,34 +70,37 @@ stepper's prompt:
             values values)))
 
 (defmethod single-step ((condition step-form-condition))
-  (let ((form (step-condition-form condition)))
-    (loop
-     (format *debug-io* "; form ~A~%STEP] " form)
-     (finish-output *debug-io*)
-     (let ((line (read-line *debug-io*)))
-       (if (plusp (length line))
-           (case (char-upcase (schar line 0))
-             (#\Q
-              (abort condition))
-             (#\C
-              (step-continue condition))
-             (#\N
-              (step-next condition))
-             (#\S
-              (step-into condition))
-             (#\?
-              (write-line *step-help* *debug-io*))))))))
-
-(defvar *stepper-hook* #'single-step
+  (let ((form (step-condition-form condition))
+        (args (step-condition-args condition)))
+    (let ((*print-circle* t)
+          (*print-pretty* t)
+          (*print-readably* nil))
+      (format *debug-io*
+              "; Evaluating call:~%~<; ~@;  ~A~:>~%~
+               ; ~:[With arguments:~%~<; ~@;~{  ~S~^~%~}~:>~;With unknown arguments~]~%"
+              (list form)
+              (eq args :unknown)
+              (list args)))
+    (finish-output *debug-io*)
+    (let ((*stack-top-hint* (sb-di::find-stepped-frame)))
+      (invoke-debugger condition))))
+
+;;; In the TTY debugger we're not interested in STEP returning
+(defmethod single-step ((condition step-finished-condition))
+  (values))
+
+(defvar *stepper-hook* 'single-step
   #+sb-doc "Customization hook for alternative single-steppers.
 *STEPPER-HOOK* is bound to NIL prior to calling the bound function
 with the STEP-CONDITION as argument.")
 
 (defun invoke-stepper (condition)
-  (when (and *stepping* *stepper-hook*)
-    (let ((hook *stepper-hook*)
-          (*stepper-hook* nil))
-      (funcall hook condition))))
+  (when (and (stepping-enabled-p)
+             *stepper-hook*)
+    (with-stepping-disabled
+      (let ((hook *stepper-hook*)
+            (*stepper-hook* nil))
+        (funcall hook condition)))))
 
 (defmacro step (form)
   #+sb-doc
@@ -74,9 +108,15 @@ with the STEP-CONDITION as argument.")
 outside the lexical scope of the form can be stepped into only if the
 functions in question have been compiled with sufficient DEBUG policy
 to be at least partially steppable."
-  `(let ((*stepping* t)
-         (*step* t))
-    (declare (optimize (sb-c:insert-step-conditions 0)))
-    (format t "Single stepping. Type ? for help.~%")
-    (locally (declare (optimize (sb-c:insert-step-conditions 3)))
-      ,form)))
+  `(locally
+       (declare (optimize debug (sb-c:insert-step-conditions 0)))
+     (format t "Single stepping. Type ? for help.~%")
+     ;; Allow stepping out of the STEP form.
+     (let ((*step-out* :maybe))
+       (unwind-protect
+            (with-stepping-enabled
+              (multiple-value-prog1
+                  (locally (declare (optimize (sb-c:insert-step-conditions 3)))
+                    ,form)
+                (step-finished)))))))
+