Skip to content

Commit

Permalink
Add errors and conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
kartik-s committed Aug 9, 2024
1 parent 5157623 commit 5a61c4e
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 0 deletions.
101 changes: 101 additions & 0 deletions src/conditions.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
(in-package #:sbcl-librarian)

(defvar *print-backtrace-in-bug* nil)

(define-condition lisp-error (cl:error)
((reason :initarg :reason
:accessor lisp-error-reason)
(args :initarg :args
:accessor lisp-error-args))
(:report (lambda (c s)
(with-slots (reason args) c
(let ((*print-circle* nil))
(format s "Lisp Error: ~?" reason args))))))

(declaim (inline error))
(defun error (reason &rest args)
(declare (type string reason))
(cl:error 'lisp-error
:reason reason
:args args))

(define-condition lisp-warning (style-warning)
((reason :initarg :reason
:accessor lisp-warning-reason)
(args :initarg :args
:accessor lisp-warning-args))
(:report (lambda (c s)
(with-slots (reason args) c
(let ((*print-circle* nil))
(format s "Lisp Warning: ~?" reason args))))))

(declaim (inline warning))
(defun warning (reason &rest args)
(cl:warn 'lisp-warning
:reason reason
:args args))

(define-condition lisp-bug (cl:error)
((reason :initarg :reason
:accessor lisp-bug-reason)
(args :initarg :args
:accessor lisp-bug-args)
(backtrace :initarg :backtrace
:accessor lisp-bug-backtrace
:initform (error "backtrace is required"))
(context :initform (list)
:accessor lisp-bug-context))
(:report (lambda (c s)
(with-slots (reason args backtrace context) c
(let ((*print-circle* nil))
(format s "Internal lisp bug: ~?~%
If you are seeing this, please file an issue on Gitlab and include this error message in the description.
~A
Context:
~{ ~{~A~^: ~}~%~}
~A"
reason
args
*gitlab-issue-url*
context
(if *print-backtrace-in-bug*
backtrace
"")))))))

(declaim (inline bug))
(defun bug (reason &rest args)
(declare (type string reason))
(cl:error 'lisp-bug
:reason reason
:args args
:backtrace (with-output-to-string (s)
(sb-debug:print-backtrace
:stream s
:start 1 ; Don't show the `bug' call
:emergency-best-effort t))))

(declaim (inline unreachable))
(defun unreachable ()
(bug "unreachable"))

(defmacro with-bug-context (context &body body)
`(handler-bind
((lisp-bug
(lambda (c)
(declare (ignorable c))
,@(mapcar (lambda (ctx)
(cl:assert (= 2 (length ctx)))
`(push (list ,@ctx) (lisp-bug-context c)))
context))))
,@body))

(defmacro assert (test-form &optional places datum arguments)
(let ((sym (gensym)))
`(with-bug-context (,@(mapcar (lambda (place)
`(,(format nil "~S" place) ,place))
places))
(let ((,sym ,test-form))
(unless ,sym
(bug ,(or datum "The assertion ~S failed")
,@(if datum arguments `(',test-form))))))))
74 changes: 74 additions & 0 deletions src/errors.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
(in-package #:sbcl-librarian)

(define-enum-type error-type "lisp_err_t"
("LISP_ERR_SUCCESS" 0)
("LISP_ERR_FAILURE" 1)
("LISP_ERR_BUG" 2)
("LISP_ERR_FATAL" 3))

(defvar *error-message* ""
"The most recent error message.")

(defun get-error-message ()
*error-message*)

(defvar *show-backtrace* nil)

(defun enable-backtrace (code)
(setf *show-backtrace* (not (zerop code))))

(defun crash ()
(error "oops"))

(defun exhaust-heap ()
(sb-sys:without-gcing
(let ((test '()))
(loop (push 1 test)))))

(define-error-map default-error-map error-type (:no-error 0 :fatal-error 3)
((warning #'continue)

(sbcl-librarian:lisp-error
(lambda (c)
(when *show-backtrace*
(sb-debug:print-backtrace
:stream *error-output*
:emergency-best-effort t))
(setf *error-message* (format nil "~A" c))
(return-from default-error-map 1)))

(sbcl-librarian:lisp-bug
(lambda (c)
(when *show-backtrace*
(sb-debug:print-backtrace
:stream *error-output*
:emergency-best-effort t))

(let ((sbcl-librarian:*print-backtrace-in-bug* t))
(setf *error-message* (format nil "~A" c)))

(return-from default-error-map 2)))

(error
(lambda (c)
(let ((bug (make-instance 'sbcl-librarian:lisp-bug
:reason (format nil "~A" c)
:args nil
:backtrace (with-output-to-string (s)
(sb-debug:print-backtrace
:stream s
:emergency-best-effort t)))))

(let ((sbcl-librarian:*print-backtrace-in-bug* t))
(setf *error-message* (format nil "~A" bug)))

(return-from default-error-map 2))))))

(sbcl-librarian:define-api errors (:error-map default-error-map)
(:literal "/* lisp */")
(:type error-type)
(:function
(get-error-message :string ())
(enable-backtrace :void ((on :int)))
(crash :void ())
(exhaust-heap :void ())))

0 comments on commit 5a61c4e

Please sign in to comment.