exception.scm 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
  2. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  3. ;;;; Raising and handling of exceptions
  4. ; A condition is a run-time system structure describing an unusual situation.
  5. ; Raising and handling conditions.
  6. ; (fluid $exception-handlers) is a cell containing a list of handler procedures.
  7. ; Each handler takes two arguments: the condition to be handled, and
  8. ; a thunk that can be called if the handler decides to decline handling
  9. ; the condition. The continuation to a call to a handler is that
  10. ; of the call to signal-condition.
  11. (define (really-signal-condition condition)
  12. (let loop ((hs (fluid-cell-ref $exception-handlers))
  13. (condition condition))
  14. ((car hs) condition
  15. (lambda maybe-condition
  16. (if (null? maybe-condition)
  17. (loop (cdr hs) condition)
  18. (loop (cdr hs) (car maybe-condition)))))))
  19. (define (with-handler h thunk)
  20. (let-fluid $exception-handlers
  21. (make-cell (cons h (fluid-cell-ref $exception-handlers)))
  22. thunk))
  23. (define $exception-handlers
  24. (make-fluid (make-cell #f)))
  25. (define (initialize-exceptions! thunk)
  26. (call-with-current-continuation
  27. (lambda (k)
  28. (fluid-cell-set! $exception-handlers
  29. (list (last-resort-exception-handler k)))
  30. (thunk))))
  31. (define (last-resort-exception-handler halt)
  32. (let ((interrupt/keyboard (enum interrupt keyboard))
  33. (losing? #f))
  34. (lambda (condition punt)
  35. (cond ((error? condition)
  36. (primitive-catch
  37. (lambda (c)
  38. (if (not losing?)
  39. (begin (set! losing? #t)
  40. (report-utter-lossage condition c)))
  41. (halt 123))))
  42. ((and (interrupt? condition)
  43. (= (cadr condition) interrupt/keyboard))
  44. (halt 2))
  45. (else
  46. (unspecific)))))) ;proceed
  47. ; This will print a list of template id's, which you can look up in
  48. ; initial.debug to get some idea of what was going on.
  49. (define (report-utter-lossage condition c)
  50. (cond ((vm-exception? condition)
  51. (debug-message "VM exception `"
  52. (vm-exception-reason condition)
  53. "' with no handler in place")
  54. (debug-message "opcode is: "
  55. (enumerand->name (vm-exception-opcode condition)
  56. op)))
  57. (else
  58. (apply debug-message
  59. (condition-type condition)
  60. " with no handler in place: "
  61. (condition-stuff condition))))
  62. (apply debug-message
  63. "stack template id's: "
  64. (map (lambda (id+pc)
  65. (if (number? (car id+pc))
  66. (string-append (number->string (car id+pc))
  67. " <- ")
  68. " <- "))
  69. (continuation-preview c))))
  70. ; Run THUNK, returning either the value returned by THUNK or any error
  71. ; that occurs.
  72. (define (ignore-errors thunk)
  73. (call-with-current-continuation
  74. (lambda (k)
  75. (with-handler (lambda (c next)
  76. (if (error? c)
  77. (k c)
  78. (next)))
  79. thunk))))
  80. ; Downgrade errors to warnings while executing THUNK. Returns #T if an
  81. ; error occured.
  82. (define (report-errors-as-warnings thunk message . irritants)
  83. (let ((condition (ignore-errors
  84. (lambda ()
  85. (thunk)
  86. #f))))
  87. (if condition
  88. (begin
  89. (apply warn message (append irritants (list condition)))
  90. #t)
  91. #f)))
  92. ; Define disclosers that are most important for error messages.
  93. (define-method &disclose ((obj :closure))
  94. (list 'procedure (template-ref (closure-template obj) 1)))
  95. (define-method &disclose ((obj :location))
  96. (list 'location (location-id obj)))
  97. ; (put 'with-handler 'scheme-indent-hook 1)
  98. ;; SRFI 34
  99. (define (with-exception-handler handler thunk)
  100. (with-handler
  101. (lambda (condition punt)
  102. (handler condition))
  103. thunk))
  104. ;; no tail recursive call to the handler here
  105. (define (raise obj)
  106. (let* ((cell (make-cell (fluid-cell-ref $exception-handlers)))
  107. (last-handler #f))
  108. (let-fluid
  109. $exception-handlers cell
  110. (lambda ()
  111. (let loop ((handlers (fluid-cell-ref $exception-handlers))
  112. (obj obj))
  113. (cell-set! cell (cdr handlers))
  114. ((car handlers) obj
  115. (lambda maybe-obj
  116. (if (null? maybe-obj)
  117. (loop (cdr handlers) obj)
  118. (loop (cdr handlers) (car maybe-obj)))))
  119. (set! last-handler (car handlers)))))
  120. (error "exception handler returned" last-handler obj)))
  121. (define-syntax guard
  122. (syntax-rules ()
  123. ((guard (var clause ...) e1 e2 ...)
  124. ((call-with-current-continuation
  125. (lambda (guard-k)
  126. (with-exception-handler
  127. (lambda (condition)
  128. ((call-with-current-continuation
  129. (lambda (handler-k)
  130. (guard-k
  131. (lambda ()
  132. (let ((var condition)) ; clauses may SET! var
  133. (guard-aux (handler-k (lambda ()
  134. (raise condition)))
  135. clause ...))))))))
  136. (lambda ()
  137. (call-with-values
  138. (lambda () e1 e2 ...)
  139. (lambda args
  140. (guard-k (lambda ()
  141. (apply values args)))))))))))))
  142. (define-syntax guard-aux
  143. (syntax-rules (else =>)
  144. ((guard-aux reraise (else result1 result2 ...))
  145. (begin result1 result2 ...))
  146. ((guard-aux reraise (test => result))
  147. (let ((temp test))
  148. (if temp
  149. (result temp)
  150. reraise)))
  151. ((guard-aux reraise (test => result) clause1 clause2 ...)
  152. (let ((temp test))
  153. (if temp
  154. (result temp)
  155. (guard-aux reraise clause1 clause2 ...))))
  156. ((guard-aux reraise (test))
  157. test)
  158. ((guard-aux reraise (test) clause1 clause2 ...)
  159. (let ((temp test))
  160. (if temp
  161. temp
  162. (guard-aux reraise clause1 clause2 ...))))
  163. ((guard-aux reraise (test result1 result2 ...))
  164. (if test
  165. (begin result1 result2 ...)
  166. reraise))
  167. ((guard-aux reraise (test result1 result2 ...) clause1 clause2 ...)
  168. (if test
  169. (begin result1 result2 ...)
  170. (guard-aux reraise clause1 clause2 ...)))))