exceptions.scm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. ;;; Exceptions
  2. ;;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
  3. ;;;
  4. ;;; This library is free software: you can redistribute it and/or modify
  5. ;;; it under the terms of the GNU Lesser General Public License as
  6. ;;; published by the Free Software Foundation, either version 3 of the
  7. ;;; License, or (at your option) any later version.
  8. ;;;
  9. ;;; This library is distributed in the hope that it will be useful, but
  10. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;; Lesser General Public License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU Lesser General Public
  15. ;;; License along with this program. If not, see
  16. ;;; <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;;;
  19. ;;; Definition of the standard exception types.
  20. ;;;
  21. ;;; Code:
  22. (define-module (ice-9 exceptions)
  23. #:re-export (&exception
  24. make-exception
  25. make-exception-type
  26. simple-exceptions
  27. exception?
  28. exception-type?
  29. exception-predicate
  30. exception-accessor
  31. exception-kind
  32. exception-args
  33. &error
  34. &programming-error
  35. &quit-exception
  36. &non-continuable
  37. raise-exception
  38. with-exception-handler)
  39. #:export (define-exception-type
  40. &message
  41. make-exception-with-message
  42. exception-with-message?
  43. exception-message
  44. &warning
  45. make-warning
  46. warning?
  47. make-error
  48. error?
  49. &external-error
  50. make-external-error
  51. external-error?
  52. make-quit-exception
  53. quit-exception?
  54. make-programming-error
  55. programming-error?
  56. &assertion-failure
  57. make-assertion-failure
  58. assertion-failure?
  59. &irritants
  60. make-exception-with-irritants
  61. exception-with-irritants?
  62. exception-irritants
  63. &origin
  64. make-exception-with-origin
  65. exception-with-origin?
  66. exception-origin
  67. make-non-continuable-error
  68. non-continuable-error?
  69. &implementation-restriction
  70. make-implementation-restriction-error
  71. implementation-restriction-error?
  72. &lexical
  73. make-lexical-error
  74. lexical-error?
  75. &syntax
  76. make-syntax-error
  77. syntax-error?
  78. syntax-error-form
  79. syntax-error-subform
  80. &undefined-variable
  81. make-undefined-variable-error
  82. undefined-variable-error?
  83. raise-continuable
  84. guard))
  85. (define-syntax define-exception-type-procedures
  86. (syntax-rules ()
  87. ((_ exception-type supertype constructor predicate
  88. (field accessor) ...)
  89. (begin
  90. (define constructor (record-constructor exception-type))
  91. (define predicate (exception-predicate exception-type))
  92. (define accessor
  93. (exception-accessor exception-type
  94. (record-accessor exception-type 'field)))
  95. ...))))
  96. (define-syntax define-exception-type
  97. (syntax-rules ()
  98. ((_ exception-type supertype constructor predicate
  99. (field accessor) ...)
  100. (begin
  101. (define exception-type
  102. (make-record-type 'exception-type '((immutable field) ...)
  103. #:parent supertype #:extensible? #t))
  104. (define-exception-type-procedures exception-type supertype
  105. constructor predicate (field accessor) ...)))))
  106. (define-exception-type-procedures &error &exception
  107. make-error error?)
  108. (define-exception-type-procedures &programming-error &error
  109. make-programming-error programming-error?)
  110. (define-exception-type &assertion-failure &programming-error
  111. make-assertion-failure assertion-failure?)
  112. (define-exception-type &message &exception
  113. make-exception-with-message exception-with-message?
  114. (message exception-message))
  115. (define-exception-type &warning &exception
  116. make-warning warning?)
  117. (define-exception-type &external-error &error
  118. make-external-error external-error?)
  119. (define-exception-type &irritants &exception
  120. make-exception-with-irritants exception-with-irritants?
  121. (irritants exception-irritants))
  122. (define-exception-type &origin &exception
  123. make-exception-with-origin exception-with-origin?
  124. (origin exception-origin))
  125. (define-exception-type-procedures &non-continuable &programming-error
  126. make-non-continuable-error
  127. non-continuable-error?)
  128. (define-exception-type &implementation-restriction &programming-error
  129. make-implementation-restriction-error
  130. implementation-restriction-error?)
  131. (define-exception-type &lexical &programming-error
  132. make-lexical-error lexical-error?)
  133. (define-exception-type &syntax &programming-error
  134. make-syntax-error syntax-error?
  135. (form syntax-error-form)
  136. (subform syntax-error-subform))
  137. (define-exception-type &undefined-variable &programming-error
  138. make-undefined-variable-error undefined-variable-error?)
  139. (define make-exception-with-kind-and-args
  140. (record-constructor &exception-with-kind-and-args))
  141. (define make-quit-exception
  142. (record-constructor &quit-exception))
  143. (define quit-exception?
  144. (exception-predicate &quit-exception))
  145. (define (default-guile-exception-converter key args)
  146. (make-exception (make-error)
  147. (guile-common-exceptions key args)))
  148. (define (guile-common-exceptions key args)
  149. (apply (case-lambda
  150. ((subr msg margs . _)
  151. (make-exception
  152. (make-exception-with-origin subr)
  153. (make-exception-with-message msg)
  154. (make-exception-with-irritants margs)))
  155. (_ (make-exception-with-irritants args)))
  156. args))
  157. (define (convert-guile-exception key args)
  158. (let ((converter (assv-ref guile-exception-converters key)))
  159. (make-exception (or (and converter (converter key args))
  160. (default-guile-exception-converter key args))
  161. (make-exception-with-kind-and-args key args))))
  162. (define (raise-continuable obj)
  163. (raise-exception obj #:continuable? #t))
  164. ;;; Exception printing
  165. (define (exception-printer port key args punt)
  166. (cond ((and (= 1 (length args))
  167. (exception? (car args)))
  168. (display "ERROR:\n" port)
  169. (format-exception port (car args)))
  170. (else
  171. (punt))))
  172. (define (format-exception port exception)
  173. (let ((components (simple-exceptions exception)))
  174. (if (null? components)
  175. (format port "Empty exception object")
  176. (let loop ((i 1) (components components))
  177. (cond ((pair? components)
  178. (format port " ~a. " i)
  179. (format-simple-exception port (car components))
  180. (when (pair? (cdr components))
  181. (newline port))
  182. (loop (+ i 1) (cdr components))))))))
  183. (define (format-simple-exception port exception)
  184. (let* ((type (struct-vtable exception))
  185. (name (record-type-name type))
  186. (fields (record-type-fields type)))
  187. (cond
  188. ((null? fields)
  189. (format port "~a" name))
  190. ((null? (cdr fields))
  191. (format port "~a: ~s" name (struct-ref exception 0)))
  192. (else
  193. (format port "~a:\n" name)
  194. (let lp ((fields fields) (i 0))
  195. (let ((field (car fields))
  196. (fields (cdr fields)))
  197. (format port " ~a: ~s" field (struct-ref exception i))
  198. (unless (null? fields)
  199. (newline port)
  200. (lp fields (+ i 1)))))))))
  201. (set-exception-printer! '%exception exception-printer)
  202. ;; Guile exception converters
  203. ;;
  204. ;; Each converter is a procedure (converter KEY ARGS) that returns
  205. ;; either an exception object or #f. If #f is returned,
  206. ;; 'default-guile-exception-converter' will be used.
  207. (define (guile-syntax-error-converter key args)
  208. (apply (case-lambda
  209. ((who what where form subform . extra)
  210. (make-exception (make-syntax-error form subform)
  211. (make-exception-with-origin who)
  212. (make-exception-with-message what)))
  213. (_ #f))
  214. args))
  215. (define make-quit-exception (record-constructor &quit-exception))
  216. (define (guile-quit-exception-converter key args)
  217. (define code
  218. (cond
  219. ((not (pair? args)) 0)
  220. ((integer? (car args)) (car args))
  221. ((not (car args)) 1)
  222. (else 0)))
  223. (make-exception (make-quit-exception code)
  224. (guile-common-exceptions key args)))
  225. (define (guile-lexical-error-converter key args)
  226. (make-exception (make-lexical-error)
  227. (guile-common-exceptions key args)))
  228. (define (guile-assertion-failure-converter key args)
  229. (make-exception (make-assertion-failure)
  230. (guile-common-exceptions key args)))
  231. (define (guile-undefined-variable-error-converter key args)
  232. (make-exception (make-undefined-variable-error)
  233. (guile-common-exceptions key args)))
  234. (define (guile-implementation-restriction-converter key args)
  235. (make-exception (make-implementation-restriction-error)
  236. (guile-common-exceptions key args)))
  237. (define (guile-external-error-converter key args)
  238. (make-exception (make-external-error)
  239. (guile-common-exceptions key args)))
  240. (define (guile-system-error-converter key args)
  241. (apply (case-lambda
  242. ((subr msg msg-args errno . rest)
  243. ;; XXX TODO we should return a more specific error
  244. ;; (usually an I/O error) as expected by R6RS programs.
  245. ;; Unfortunately this often requires the 'filename' (or
  246. ;; other?) which is not currently provided by the native
  247. ;; Guile exceptions.
  248. (make-exception (make-external-error)
  249. (guile-common-exceptions key args)))
  250. (_ (guile-external-error-converter key args)))
  251. args))
  252. ;; TODO: Arrange to have the needed information included in native
  253. ;; Guile I/O exceptions, and arrange here to convert them to the
  254. ;; proper exceptions. Remove the earlier exception conversion
  255. ;; mechanism: search for 'with-throw-handler' in the 'rnrs'
  256. ;; tree, e.g. 'with-i/o-filename-exceptions' and
  257. ;; 'with-i/o-port-error' in (rnrs io ports).
  258. ;; XXX TODO: How should we handle the 'misc-error', 'vm-error', and
  259. ;; 'signal' native Guile exceptions?
  260. ;; XXX TODO: Should we handle the 'quit' exception specially?
  261. ;; An alist mapping native Guile exception keys to converters.
  262. (define guile-exception-converters
  263. `((quit . ,guile-quit-exception-converter)
  264. (read-error . ,guile-lexical-error-converter)
  265. (syntax-error . ,guile-syntax-error-converter)
  266. (unbound-variable . ,guile-undefined-variable-error-converter)
  267. (wrong-number-of-args . ,guile-assertion-failure-converter)
  268. (wrong-type-arg . ,guile-assertion-failure-converter)
  269. (keyword-argument-error . ,guile-assertion-failure-converter)
  270. (out-of-range . ,guile-assertion-failure-converter)
  271. (regular-expression-syntax . ,guile-assertion-failure-converter)
  272. (program-error . ,guile-assertion-failure-converter)
  273. (goops-error . ,guile-assertion-failure-converter)
  274. (null-pointer-error . ,guile-assertion-failure-converter)
  275. (system-error . ,guile-system-error-converter)
  276. (host-not-found . ,guile-external-error-converter)
  277. (getaddrinfo-error . ,guile-external-error-converter)
  278. (no-data . ,guile-external-error-converter)
  279. (no-recovery . ,guile-external-error-converter)
  280. (try-again . ,guile-external-error-converter)
  281. (stack-overflow . ,guile-implementation-restriction-converter)
  282. (numerical-overflow . ,guile-implementation-restriction-converter)
  283. (memory-allocation-error . ,guile-implementation-restriction-converter)))
  284. (define (set-guile-exception-converter! key proc)
  285. (set! guile-exception-converters
  286. (acons key proc guile-exception-converters)))
  287. ;; Override core definition.
  288. (set! make-exception-from-throw convert-guile-exception)
  289. (define-syntax guard
  290. (lambda (stx)
  291. "Establish an exception handler during the evaluation of an expression.
  292. @example
  293. (guard (@var{exn} @var{clause1} @var{clause2} ...)
  294. @var{body} @var{body*} ...)
  295. @end example
  296. Each @var{clause} should have the same form as a @code{cond} clause.
  297. The @code{(begin body body* ...)} is evaluated with an exception
  298. handler that binds the raised object to @var{exn} and within the scope of
  299. that binding evaluates the clauses as if they were the clauses of a cond
  300. expression.
  301. When a clause of that implicit cond expression matches, its consequent
  302. is evaluated with the continuation and dynamic environment of the
  303. @code{guard} expression.
  304. If every clause's test evaluates to false and there is no @code{else}
  305. clause, then @code{raise-continuable} is re-invoked on the raised
  306. object, within the dynamic environment of the original call to raise
  307. except that the current exception handler is that of the guard
  308. expression.
  309. Note that in a slight deviation from SRFI-34, R6RS, and R7RS, Guile
  310. evaluates the clause tests within the continuation of the exception
  311. handler, not the continuation of the @code{guard}. This allows
  312. unhandled exceptions to continue to dispatch within the original
  313. continuation, without unwinding then rewinding any intermediate
  314. @code{dynamic-wind} invocations."
  315. (define (dispatch tag exn clauses)
  316. (define (build-clause test handler clauses)
  317. #`(let ((t #,test))
  318. (if t
  319. (abort-to-prompt #,tag #,handler t)
  320. #,(dispatch tag exn clauses))))
  321. (syntax-case clauses (=> else)
  322. (() #`(raise-continuable #,exn))
  323. (((test => f) . clauses)
  324. (build-clause #'test #'(lambda (res) (f res)) #'clauses))
  325. (((else e e* ...) . clauses)
  326. (build-clause #'#t #'(lambda (res) e e* ...) #'clauses))
  327. (((test) . clauses)
  328. (build-clause #'test #'(lambda (res) res) #'clauses))
  329. (((test e* ...) . clauses)
  330. (build-clause #'test #'(lambda (res) e* ...) #'clauses))))
  331. (syntax-case stx ()
  332. ((guard (exn clause clause* ...) body body* ...)
  333. (identifier? #'exn)
  334. #`(let ((tag (make-prompt-tag)))
  335. (call-with-prompt
  336. tag
  337. (lambda ()
  338. (with-exception-handler
  339. (lambda (exn)
  340. #,(dispatch #'tag #'exn #'(clause clause* ...)))
  341. (lambda () body body* ...)))
  342. (lambda (_ h v)
  343. (h v))))))))