(load "macros.scm") ;; guile style exceptions implemented using continuations ;; exception stack. ;; an exception is a (key contunuation handler) list (define *exceptions* '()) ;; check if a key matches an exception (define (key-match? key exception) (let ((e-key (car exception))) (or (eq? e-key #t) (eq? e-key key)))) ;; perform an exception (define (do-handler args exception) (apply (lambda (key cont handler) (cont (apply handler args))) exception)) ;; throw: pop exception stack till we find a handler (define (throw . args) (let ((exception (pop *exceptions*)) (key (car args))) (apply (if (key-match? key exception) (do-handler args exception) (apply do-throw args))))) ;; catch: save continuation, evaluate, cleanup (define (catch key thunk handle) (call/cc (lambda (cont) ;; get the continuation of the catch expression (push *exceptions* ;; push an exception handler data structure (list key cont handle)) (let ((value (thunk))) ;; evaluate. throw will invoke the continuation (pop *exceptions*) ;; remove the handler before returning value value))))