;; (C) 2008, 2010 Joerg F. Wittenberger see http://www.askemos.org ;; Try to be nice and mix+match with chickens native error handling. ;; Could probably be much mor efficient if we did not do so. (declare (unit srfi-34) (fixnum-arithmetic) (disable-interrupts) (usual-integrations) (no-bound-checks) (no-procedure-checks-for-usual-bindings) (bound-to-procedure ##sys#current-exception-handler ##sys#check-symbol ##sys#symbol->string symbol->string ##sys#make-structure ##sys#structure? ##sys#check-structure) ) (module srfi-34 ( guard with-exception-handler with-exception-guard raise ) (import scheme (only chicken make-parameter) (prefix srfi-18 s18:) (prefix chicken s18:)) (define (error msg . args) (##sys#abort (##sys#make-structure 'condition '(exn) (list '(exn . message) msg '(exn . arguments) args '(exn . location) #f) ) )) (define *current-exception-handlers* (make-parameter (list ##sys#current-exception-handler))) (define (with-exception-handlers new-handlers thunk) (let ((previous-handlers (*current-exception-handlers*)) [oldh ##sys#current-exception-handler]) (dynamic-wind (lambda () (set! ##sys#current-exception-handler ##sys#raise) (*current-exception-handlers* new-handlers)) thunk (lambda () (set! ##sys#current-exception-handler oldh) (*current-exception-handlers* previous-handlers))))) (define (with-exception-handler handler thunk) (with-exception-handlers (cons handler (*current-exception-handlers*)) thunk)) (define (##sys#raise obj) (let ((handlers (*current-exception-handlers*))) (with-exception-handlers (cdr handlers) (lambda () ((car handlers) obj) (error "handler returned" (car handlers) obj))))) (define raise ##sys#raise) (set! ##sys#current-exception-handler ##sys#raise) (set! s18:with-exception-handler with-exception-handler) (define-syntax guard (syntax-rules () ((guard (var clause ...) e1 e2 ...) ((call-with-current-continuation (lambda (guard-k) (with-exception-handler (lambda (condition) ((call-with-current-continuation (lambda (handler-k) (guard-k (lambda () (let ((var condition)) ; clauses may SET! var (guard-aux (handler-k (lambda () (raise condition))) clause ...)))))))) (lambda () (call-with-values (lambda () e1 e2 ...) (lambda args (guard-k (lambda () (apply values args))))))))))))) (define-syntax guard-aux (syntax-rules (else =>) ((guard-aux reraise (else result1 result2 ...)) (begin result1 result2 ...)) ((guard-aux reraise (test => result)) (let ((temp test)) (if temp (result temp) reraise))) ((guard-aux reraise (test => result) clause1 clause2 ...) (let ((temp test)) (if temp (result temp) (guard-aux reraise clause1 clause2 ...)))) ((guard-aux reraise (test)) test) ((guard-aux reraise (test) clause1 clause2 ...) (let ((temp test)) (if temp temp (guard-aux reraise clause1 clause2 ...)))) ((guard-aux reraise (test result1 result2 ...)) (if test (begin result1 result2 ...) reraise)) ((guard-aux reraise (test result1 result2 ...) clause1 clause2 ...) (if test (begin result1 result2 ...) (guard-aux reraise clause1 clause2 ...))))) ; (define raise s18:raise) (define (with-exception-guard handler thunk) ((call-with-current-continuation (lambda (return) (let ((oldh (s18:current-exception-handler))) (with-exception-handler (lambda (condition) (with-exception-handler oldh (call-with-current-continuation (lambda (handler-k) (return (lambda () (handler condition))))))) (lambda () (##sys#call-with-values thunk (lambda args (return (lambda () (##sys#apply ##sys#values args)))) ) ) )) ) )) ) )