exception.scm 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
  2. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  3. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber
  4. ;;;; Raising and handling of exceptions
  5. ; A condition is a run-time system structure describing an unusual situation.
  6. ; Raising and handling conditions.
  7. ; (fluid $exception-handlers) is a cell containing a list of handler procedures.
  8. ; Each handler takes two arguments: the condition to be handled, and
  9. ; a thunk that can be called if the handler decides to decline handling
  10. ; the condition. The continuation to a call to a handler is that
  11. ; of the call to signal-condition.
  12. (define (really-signal-condition condition)
  13. (let loop ((hs (fluid-cell-ref $exception-handlers))
  14. (condition condition))
  15. ((car hs) condition
  16. (lambda maybe-condition
  17. (if (null? maybe-condition)
  18. (loop (cdr hs) condition)
  19. (loop (cdr hs) (car maybe-condition)))))))
  20. (define (with-handler h thunk)
  21. (let-fluid $exception-handlers
  22. (make-cell (cons h (fluid-cell-ref $exception-handlers)))
  23. thunk))
  24. (define $exception-handlers
  25. (make-fluid (make-cell #f)))
  26. (define (initialize-exceptions! thunk)
  27. (call-with-current-continuation
  28. (lambda (k)
  29. (fluid-cell-set! $exception-handlers
  30. (list (last-resort-exception-handler k)))
  31. (initialize-vm-exceptions! really-signal-condition)
  32. (thunk))))
  33. (define (last-resort-exception-handler halt)
  34. (let ((interrupt/keyboard (enum interrupt keyboard))
  35. (losing? #f))
  36. (lambda (condition punt)
  37. (cond ((serious-condition? condition)
  38. (primitive-catch
  39. (lambda (c)
  40. (if (not losing?)
  41. (begin (set! losing? #t)
  42. (report-utter-lossage condition c)))
  43. (halt 123))))
  44. ((and (interrupt-condition? condition)
  45. (= (interrupt-source condition) interrupt/keyboard))
  46. (halt 2))
  47. (else
  48. (unspecific)))))) ;proceed
  49. ; This will print a list of template id's, which you can look up in
  50. ; initial.debug to get some idea of what was going on.
  51. (define (report-utter-lossage condition c)
  52. (cond ((vm-exception? condition)
  53. (debug-message "VM exception `"
  54. (vm-exception-reason condition)
  55. "' with no handler in place")
  56. (debug-message "opcode is: "
  57. (enumerand->name (vm-exception-opcode condition)
  58. op)))
  59. (else
  60. (call-with-values
  61. (lambda () (decode-condition condition))
  62. (lambda (type who message stuff)
  63. (apply debug-message
  64. type
  65. " [" who "]"
  66. " with no handler in place: "
  67. message
  68. stuff)))))
  69. (apply debug-message
  70. "stack template id's: "
  71. (map (lambda (id+pc)
  72. (if (number? (car id+pc))
  73. (string-append (number->string (car id+pc))
  74. " <- ")
  75. " <- "))
  76. (continuation-preview c))))
  77. ; Run THUNK, returning either the value returned by THUNK or any error
  78. ; that occurs.
  79. (define (ignore-errors thunk)
  80. (call-with-current-continuation
  81. (lambda (k)
  82. (with-handler (lambda (c next)
  83. (if (serious-condition? c)
  84. (k c)
  85. (next)))
  86. thunk))))
  87. ; Downgrade errors to warnings while executing THUNK. Returns #T if an
  88. ; error occured.
  89. (define (report-errors-as-warnings thunk message . irritants)
  90. (let ((condition (ignore-errors
  91. (lambda ()
  92. (thunk)
  93. #f))))
  94. (if condition
  95. (begin
  96. (apply warning 'report-errors-as-warnings
  97. message
  98. (append irritants (list condition)))
  99. #t)
  100. #f)))
  101. ; Define disclosers that are most important for error messages.
  102. (define-method &disclose ((obj <closure>))
  103. (list 'procedure (template-ref (closure-template obj) 1)))
  104. (define-method &disclose ((obj <location>))
  105. (list 'location (location-id obj)))
  106. ; (put 'with-handler 'scheme-indent-hook 1)
  107. ;; SRFI 34
  108. (define (with-exception-handler handler thunk)
  109. (with-handler
  110. (lambda (condition punt)
  111. (handler condition))
  112. thunk))
  113. (define (raise obj)
  114. (let* ((cell (make-cell (fluid-cell-ref $exception-handlers)))
  115. (current-handler #f))
  116. (let-fluid
  117. $exception-handlers cell
  118. (lambda ()
  119. (let loop ((handlers (fluid-cell-ref $exception-handlers))
  120. (obj obj))
  121. (let ((rest (cdr handlers)))
  122. (cell-set! cell rest)
  123. (set! current-handler (car handlers))
  124. (current-handler obj
  125. (lambda maybe-obj
  126. (if (null? maybe-obj)
  127. (loop rest obj)
  128. (loop rest (car maybe-obj)))))))
  129. (if (pair? (cell-ref cell)) ; don't skip the last one
  130. (assertion-violation 'raise "exception handler returned"
  131. current-handler obj))))
  132. ;; go back to the top
  133. (assertion-violation 'raise "exception handler returned"
  134. current-handler obj)))
  135. (define (raise-continuable obj)
  136. (let* ((cell (make-cell (fluid-cell-ref $exception-handlers))))
  137. (let-fluid
  138. $exception-handlers cell
  139. (lambda ()
  140. (let loop ((handlers (fluid-cell-ref $exception-handlers))
  141. (obj obj))
  142. (cell-set! cell (cdr handlers))
  143. ((car handlers) obj
  144. (lambda maybe-obj
  145. (if (null? maybe-obj)
  146. (loop (cdr handlers) obj)
  147. (loop (cdr handlers) (car maybe-obj))))))))))
  148. (define-syntax guard
  149. (syntax-rules ()
  150. ((guard (var clause ...) e1 e2 ...)
  151. ((call-with-current-continuation
  152. (lambda (guard-k)
  153. (with-exception-handler
  154. (lambda (condition)
  155. ((call-with-current-continuation
  156. (lambda (handler-k)
  157. (guard-k
  158. (lambda ()
  159. (let ((var condition)) ; clauses may SET! var
  160. (guard-aux (handler-k (lambda ()
  161. (raise-continuable condition)))
  162. clause ...))))))))
  163. (lambda ()
  164. (call-with-values
  165. (lambda () e1 e2 ...)
  166. (lambda args
  167. (guard-k (lambda ()
  168. (apply values args)))))))))))))
  169. (define-syntax guard-aux
  170. (syntax-rules (else =>)
  171. ((guard-aux reraise (else result1 result2 ...))
  172. (begin result1 result2 ...))
  173. ((guard-aux reraise (test => result))
  174. (let ((temp test))
  175. (if temp
  176. (result temp)
  177. reraise)))
  178. ((guard-aux reraise (test => result) clause1 clause2 ...)
  179. (let ((temp test))
  180. (if temp
  181. (result temp)
  182. (guard-aux reraise clause1 clause2 ...))))
  183. ((guard-aux reraise (test))
  184. test)
  185. ((guard-aux reraise (test) clause1 clause2 ...)
  186. (let ((temp test))
  187. (if temp
  188. temp
  189. (guard-aux reraise clause1 clause2 ...))))
  190. ((guard-aux reraise (test result1 result2 ...))
  191. (if test
  192. (begin result1 result2 ...)
  193. reraise))
  194. ((guard-aux reraise (test result1 result2 ...) clause1 clause2 ...)
  195. (if test
  196. (begin result1 result2 ...)
  197. (guard-aux reraise clause1 clause2 ...)))))
  198. (define (make-general-condition con who message irritants)
  199. (apply condition
  200. con
  201. (make-message-condition message)
  202. (make-irritants-condition irritants)
  203. (if who
  204. (list (make-who-condition who))
  205. '())))
  206. (define (raise-general-trouble con who message irritants)
  207. (raise (make-general-condition con who message irritants)))
  208. (define (error who message . irritants)
  209. (raise-general-trouble (make-error)
  210. who message irritants))
  211. (define (assertion-violation who message . irritants)
  212. (raise-general-trouble (make-assertion-violation)
  213. who message irritants))
  214. (define-syntax assert
  215. (syntax-rules ()
  216. ((assert ?exp)
  217. (or ?exp
  218. (assertion-violation 'assert "assertion returned #f" '?exp)))))
  219. (define (implementation-restriction-violation who message . irritants)
  220. (raise-general-trouble (make-implementation-restriction-violation)
  221. who message irritants))
  222. (define (warning who message . irritants)
  223. (signal-condition
  224. (make-general-condition (make-warning)
  225. who message irritants)))
  226. (define (note who message . irritants)
  227. (signal-condition
  228. (make-general-condition (make-note)
  229. who message irritants)))
  230. (define (syntax-violation who message form . maybe-subform)
  231. (raise-general-trouble (make-syntax-violation form
  232. (and (pair? maybe-subform)
  233. (car maybe-subform)))
  234. who message '()))
  235. ; Set LOW-EXCEPTIONS straight
  236. (initialize-low-exception-procedures!
  237. error assertion-violation implementation-restriction-violation
  238. warning note
  239. syntax-violation)