borodust / cl-bodge

Feature-rich game framework for Common Lisp
http://borodust.org/projects/cl-bodge/
MIT License
174 stars 14 forks source link

[bodgy-utils] invoke-bodgy interfering with step debugger #105

Closed AkashaP closed 3 years ago

AkashaP commented 3 years ago

I think step is useful for debugging game logic, the closest alternative is sly stickers but they do not provide step into/out/next restarts and only work if the implementation supports break-on-stickers.

I'm having issues with step not entering the form i expect. This can be seen on the default hello-gamekit project, just wrap (step ...) the snake logic:

hello-gamekit.lisp gamekit:act method

(step
        (progn
          (update-position (aref *curve* 1) (real-time-seconds))
          (update-position (aref *curve* 2) (+ 0.1 (real-time-seconds)))))

EDIT: Note you need debug set to 3 in SBCL to get this to work in SBCL specifically. this can be done by putting this in .sbclrc (sb-ext:restrict-compiler-policy 'debug 3 3)

this should normally drop into aref or real-time-seconds and then prompt for step restarts on it, but because the step facility in SBCL uses conditions it interferes with bodgy instead i am dragged into the invoke-bodgy function in bodge-utilities package and after stepping from all the way back here all the conditions coming from step gets printed out to the repl.

The code catching the step conditions is here: https://github.com/borodust/bodge-utilities/blob/6304bac4abe06d53579e2c0fc4437d14ff077d9f/src/utils.lisp#L19

(handler-bind ((serious-condition ...))
  ;; sb-ext:step-form-condition, sb-ext:step-finished-condition and sb-ext:step-values-condition are caught by this
  (t (lambda (e)
       (with-error-report-string (error-text) e
         (log:warn "~A" error-text))))
  ...)

i don't know if there is a way from within the handler system to stop step from bubbling up to invoke-bodgy and still have it show up in sly so currently my best solution is to just comment out the catch-all form

(defun invoke-bodgy (fu)
  (macrolet ((with-error-report-string ((report) c &body body)
               (once-only (c)
                 `(dissect:with-capped-stack ()
                    (let ((,report (with-output-to-string (stream)
                                     (format stream "Unhandled condition:~%")
                                     (dissect:present ,c stream))))
                      ,@body)))))
    (block skippable
      (handler-bind ((serious-condition (lambda (e)
                                          (with-error-report-string (error-text) e
                                            (log:error "~A" error-text)
                                            (in-development-mode
                                             (raise-ignorable e))
                                            (return-from skippable))))
                     ;; (t (lambda (e)
                     ;;      (with-error-report-string (error-text) e
                     ;;        (log:warn "~A" error-text))))
                     )
        (dissect:with-truncated-stack ()
          (funcall fu))))))

After forking and changing the source code the program does not work for some reason so I find i have to redownload the entire bodge library again using the instructions on the website, leaving the fork in local-projects so it becomes preferred by quicklisp.

Now the step form works as expected, but then of course the other errors won't be logged.

borodust commented 3 years ago

Looks like this is enough to avoid the problem: https://github.com/borodust/bodge-utilities/commit/6005b8de53ced99a3da2c176ca48be23cc559bc8 I guess, cloning only bodge-utilties into ~/quicklisp/local-projects should be enough. But it certainly possible that interface has changed.

AkashaP commented 3 years ago

brilliant!

AkashaP commented 2 years ago

i dont know why but the t condition seems to override all other conditions in a handler-bind. I had to change it to 'warning'. feels rather odd that t takes priority, is that a bug on SBCL's side?

borodust commented 2 years ago

I think runtime goes from top to bottom, until it hits compatible condition class. So if there's t on the top, it will shadow everything below.