Reputation: 1091
So consider the following code:
(define-condition some-condition (error) nil)
(defmethod print-object ((obj some-condition) stream)
(format stream "HELLO THERE"))
(defmacro error-report-test-aux (fn-to-cause-error error-type-to-catch fn-to-handle-error expected-message)
`(let ((result-message
(handler-case (funcall ,fn-to-cause-error)
(,error-type-to-catch (e) (funcall ,fn-to-handle-error e)))))
(assert (string= result-message
,expected-message))
t))
I can use it like so:
(error-report-test-aux (lambda () (error 'some-condition))
some-condition
#'princ-to-string
"HELLO THERE")
But I wanted to make error-report-test-aux
a function instead of macro, so that i can pass to it a type of condition within a variable.
To simply write defun
instead of defmacro
and remove backquote and commas doesn't work because handler-case
is macro and it doesn't evaluate error-type-to-catch
.
My question is: Is there something like handler-case
that would evaluate it's arguments (specifically condition type argument)?
Upvotes: 3
Views: 328
Reputation: 60004
Yes and no :-)
There is no standard function that would do what you want because catching errors requires establishing bindings and one usually want to bind constant symbols (like in let
/let*
) because it is easier to optimize.
You might consider creating a "universal" handler using handler-bind
and then declining to handle "uninteresting" conditions (as suggested by @jkiiski in comments), but I am not sure if that fits your exact requirements (untested!):
(defun error-report-test-aux (fn-to-cause-error error-type-to-catch expected-message)
(catch 'trap
(handler-bind ((error
(lambda (condition)
(when (typep condition error-type-to-catch)
(throw 'trap (string= (princ-to-string condition)
expected-message))))))
(funcall fn-to-cause-error))))
IF your implementation implements handler-case
/handler-bind
by binding an internal global variable, you can use progv
to bind it yourself and thus implement your error-report-test-aux
as a function.
This is probably not the best idea (your code becomes wedded to a specific implementation).
You can use the fact that some-condition
names a CLOS class and use generic functions instead of the macro.
Upvotes: 5