This is the mail archive of the kawa@sourceware.org mailing list for the Kawa project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: R6RS exceptions


Helmut Eller wrote:
does or will Kawa support R6RS style exception handling?

Not yet. Full support may take a while, but I'd like to get closer!

I'd like to use with-exception-handler to implement a debugger which is
invoked in the dynamic extend of the error, ie. the stack-frames which
caused the error are still alive so that local variables can be
inspected.  The debugger is supposed to work like the Emacs Lisp
debugger when `debug-on-error' is set.

There is an implementation in srfi34.scm which looks so:

  (define (with-exception-handler handler thunk)
    (try-catch
     (thunk)
     (ex <raise-object-exception> (handler (*:.value ex)))
     (ex <java.lang.Throwable> (handler ex))))

  (define (raise obj)
    (primitive-throw (make <raise-object-exception> obj)))

unfortunately this unwinds the stack before invoking the handler, which
is what I'd like to avoid.  If I read the R6RS correctly, raise
shouldn't unwind the stack but should instead call the current handler.
(The handler can unwind the stack, but it could also invoke a debugger.)

I agree - that implementation isn't right. We need to maintain the current handler using thread-local storage. Using the existing parameter mechanism seems a plausible way to so so.

Using untested code based on the R6RS reference implementation,
perhaps something more like:

(define current-exception-handlers
   (make-parameter
    (list (handle-unhandled condition))))

(define (handle-unhandled cond)
  (let ((exception (wrap-as-exception cond)))
    (if (serious-condition? cond)
	(primitive-throw cond)
	(format (standard-error-port) "~s~%~!" cond))))

(define (raise obj)
  (let ((handlers (current-exception-handlers)))
    (parameterize ((current-exception-handlers (cdr handlers)))
      (lambda ()
        ((car handlers) obj)
        (handle-non-continuable raise
                                 'raise
                                 (car handlers)
                                 obj)))))

(define (raise-continuable obj)
  (let ((handlers (current-exception-handlers)))
    (parameterize ((current-exception-handlers (cdr handlers)))
      (lambda ()
        ((car handlers) obj)))))

(define (handle-non-continuable raise who . irritants)
  (primitive-throw (make <raise-object-exception> obj)))

(define (with-exception-handler handler thunk)
  ;; Should we handle arbitrary Throwables?  Probably.
  (parameterize ((current-exception-handlers
                 (cons handler (current-exception-handlers))))
                thunk))

Re-implementing guard becomes a bit tricky.  The reference
implementation uses call-with-current-continuation.  That
might work (it looks like it only needs the continuation
support that kawa provides), but ugly and inefficient.

Better if we can "inline" the guard body, by putting the
body inside a try-catch.  Maybe something like this:

(define-simple-class <guard-matched> (<java.lang.Throwable>)
  (value)
  ((*init* value)
   (set! (*:.value (this)) value)))

(define-syntax guard
  (syntax-rules ()
    ((guard (var clauses ...) . body)
     (try-catch
      (with-exception-handler
       (lambda (var)
	 (primitive-throw (make <uard-matched>
			    (cond clauses ... (else (raise var)))))))
      (ex <guard-matched>
	  ex:value)))))

If you want to try to get something based on these idea working,
it would be much appreciated.  Otherwise, I'll put it on my
list, and try to get to it when I get a chance.
--
	--Per Bothner
per@bothner.com   http://per.bothner.com/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]