exceptions.scm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. ;;; Exceptions
  2. ;;; Copyright (C) 2019 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. &non-continuable
  36. raise-exception
  37. with-exception-handler)
  38. #:export (define-exception-type
  39. &message
  40. make-exception-with-message
  41. exception-with-message?
  42. exception-message
  43. &warning
  44. make-warning
  45. warning?
  46. make-error
  47. error?
  48. &external-error
  49. make-external-error
  50. external-error?
  51. make-programming-error
  52. programming-error?
  53. &assertion-failure
  54. make-assertion-failure
  55. assertion-failure?
  56. &irritants
  57. make-exception-with-irritants
  58. exception-with-irritants?
  59. exception-irritants
  60. &origin
  61. make-exception-with-origin
  62. exception-with-origin?
  63. exception-origin
  64. make-non-continuable-error
  65. non-continuable-error?
  66. &implementation-restriction
  67. make-implementation-restriction-error
  68. implementation-restriction-error?
  69. &lexical
  70. make-lexical-error
  71. lexical-error?
  72. &syntax
  73. make-syntax-error
  74. syntax-error?
  75. syntax-error-form
  76. syntax-error-subform
  77. &undefined-variable
  78. make-undefined-variable-error
  79. undefined-variable-error?
  80. raise-continuable))
  81. (define-syntax define-exception-type-procedures
  82. (syntax-rules ()
  83. ((_ exception-type supertype constructor predicate
  84. (field accessor) ...)
  85. (begin
  86. (define constructor (record-constructor exception-type))
  87. (define predicate (exception-predicate exception-type))
  88. (define accessor
  89. (exception-accessor exception-type
  90. (record-accessor exception-type 'field)))
  91. ...))))
  92. (define-syntax define-exception-type
  93. (syntax-rules ()
  94. ((_ exception-type supertype constructor predicate
  95. (field accessor) ...)
  96. (begin
  97. (define exception-type
  98. (make-record-type 'exception-type '((immutable field) ...)
  99. #:parent supertype #:extensible? #t))
  100. (define-exception-type-procedures exception-type supertype
  101. constructor predicate (field accessor) ...)))))
  102. (define-exception-type-procedures &error &exception
  103. make-error error?)
  104. (define-exception-type-procedures &programming-error &error
  105. make-programming-error programming-error?)
  106. (define-exception-type &assertion-failure &programming-error
  107. make-assertion-failure assertion-failure?)
  108. (define-exception-type &message &exception
  109. make-exception-with-message exception-with-message?
  110. (message exception-message))
  111. (define-exception-type &warning &exception
  112. make-warning warning?)
  113. (define-exception-type &external-error &error
  114. make-external-error external-error?)
  115. (define-exception-type &irritants &exception
  116. make-exception-with-irritants exception-with-irritants?
  117. (irritants exception-irritants))
  118. (define-exception-type &origin &exception
  119. make-exception-with-origin exception-with-origin?
  120. (origin exception-origin))
  121. (define-exception-type-procedures &non-continuable &programming-error
  122. make-non-continuable-error
  123. non-continuable-error?)
  124. (define-exception-type &implementation-restriction &programming-error
  125. make-implementation-restriction-error
  126. implementation-restriction-error?)
  127. (define-exception-type &lexical &programming-error
  128. make-lexical-error lexical-error?)
  129. (define-exception-type &syntax &programming-error
  130. make-syntax-error syntax-error?
  131. (form syntax-error-form)
  132. (subform syntax-error-subform))
  133. (define-exception-type &undefined-variable &programming-error
  134. make-undefined-variable-error undefined-variable-error?)
  135. (define make-exception-with-kind-and-args
  136. (record-constructor &exception-with-kind-and-args))
  137. (define make-quit-exception
  138. (record-constructor &quit-exception))
  139. (define (default-guile-exception-converter key args)
  140. (make-exception (make-error)
  141. (guile-common-exceptions key args)))
  142. (define (guile-common-exceptions key args)
  143. (apply (case-lambda
  144. ((subr msg margs . _)
  145. (make-exception
  146. (make-exception-with-origin subr)
  147. (make-exception-with-message msg)
  148. (make-exception-with-irritants margs)))
  149. (_ (make-exception-with-irritants args)))
  150. args))
  151. (define (convert-guile-exception key args)
  152. (let ((converter (assv-ref guile-exception-converters key)))
  153. (make-exception (or (and converter (converter key args))
  154. (default-guile-exception-converter key args))
  155. (make-exception-with-kind-and-args key args))))
  156. (define (raise-continuable obj)
  157. (raise-exception obj #:continuable? #t))
  158. ;;; Exception printing
  159. (define (exception-printer port key args punt)
  160. (cond ((and (= 1 (length args))
  161. (exception? (car args)))
  162. (display "ERROR:\n" port)
  163. (format-exception port (car args)))
  164. (else
  165. (punt))))
  166. (define (format-exception port exception)
  167. (let ((components (simple-exceptions exception)))
  168. (if (null? components)
  169. (format port "Empty exception object")
  170. (let loop ((i 1) (components components))
  171. (cond ((pair? components)
  172. (format port " ~a. " i)
  173. (format-simple-exception port (car components))
  174. (when (pair? (cdr components))
  175. (newline port))
  176. (loop (+ i 1) (cdr components))))))))
  177. (define (format-simple-exception port exception)
  178. (let* ((type (struct-vtable exception))
  179. (name (record-type-name type))
  180. (fields (record-type-fields type)))
  181. (cond
  182. ((null? fields)
  183. (format port "~a" name))
  184. ((null? (cdr fields))
  185. (format port "~a: ~s" name (struct-ref exception 0)))
  186. (else
  187. (format port "~a:\n" name)
  188. (let lp ((fields fields) (i 0))
  189. (let ((field (car fields))
  190. (fields (cdr fields)))
  191. (format port " ~a: ~s" field (struct-ref exception i))
  192. (unless (null? fields)
  193. (newline port)
  194. (lp fields (+ i 1)))))))))
  195. (set-exception-printer! '%exception exception-printer)
  196. ;; Guile exception converters
  197. ;;
  198. ;; Each converter is a procedure (converter KEY ARGS) that returns
  199. ;; either an exception object or #f. If #f is returned,
  200. ;; 'default-guile-exception-converter' will be used.
  201. (define (guile-syntax-error-converter key args)
  202. (apply (case-lambda
  203. ((who what where form subform . extra)
  204. (make-exception (make-syntax-error form subform)
  205. (make-exception-with-origin who)
  206. (make-exception-with-message what)))
  207. (_ #f))
  208. args))
  209. (define make-quit-exception (record-constructor &quit-exception))
  210. (define (guile-quit-exception-converter key args)
  211. (define code
  212. (cond
  213. ((not (pair? args)) 0)
  214. ((integer? (car args)) (car args))
  215. ((not (car args)) 1)
  216. (else 0)))
  217. (make-exception (make-quit-exception code)
  218. (guile-common-exceptions key args)))
  219. (define (guile-lexical-error-converter key args)
  220. (make-exception (make-lexical-error)
  221. (guile-common-exceptions key args)))
  222. (define (guile-assertion-failure-converter key args)
  223. (make-exception (make-assertion-failure)
  224. (guile-common-exceptions key args)))
  225. (define (guile-undefined-variable-error-converter key args)
  226. (make-exception (make-undefined-variable-error)
  227. (guile-common-exceptions key args)))
  228. (define (guile-implementation-restriction-converter key args)
  229. (make-exception (make-implementation-restriction-error)
  230. (guile-common-exceptions key args)))
  231. (define (guile-external-error-converter key args)
  232. (make-exception (make-external-error)
  233. (guile-common-exceptions key args)))
  234. (define (guile-system-error-converter key args)
  235. (apply (case-lambda
  236. ((subr msg msg-args errno . rest)
  237. ;; XXX TODO we should return a more specific error
  238. ;; (usually an I/O error) as expected by R6RS programs.
  239. ;; Unfortunately this often requires the 'filename' (or
  240. ;; other?) which is not currently provided by the native
  241. ;; Guile exceptions.
  242. (make-exception (make-external-error)
  243. (guile-common-exceptions key args)))
  244. (_ (guile-external-error-converter key args)))
  245. args))
  246. ;; TODO: Arrange to have the needed information included in native
  247. ;; Guile I/O exceptions, and arrange here to convert them to the
  248. ;; proper exceptions. Remove the earlier exception conversion
  249. ;; mechanism: search for 'with-throw-handler' in the 'rnrs'
  250. ;; tree, e.g. 'with-i/o-filename-exceptions' and
  251. ;; 'with-i/o-port-error' in (rnrs io ports).
  252. ;; XXX TODO: How should we handle the 'misc-error', 'vm-error', and
  253. ;; 'signal' native Guile exceptions?
  254. ;; XXX TODO: Should we handle the 'quit' exception specially?
  255. ;; An alist mapping native Guile exception keys to converters.
  256. (define guile-exception-converters
  257. `((quit . ,guile-quit-exception-converter)
  258. (read-error . ,guile-lexical-error-converter)
  259. (syntax-error . ,guile-syntax-error-converter)
  260. (unbound-variable . ,guile-undefined-variable-error-converter)
  261. (wrong-number-of-args . ,guile-assertion-failure-converter)
  262. (wrong-type-arg . ,guile-assertion-failure-converter)
  263. (keyword-argument-error . ,guile-assertion-failure-converter)
  264. (out-of-range . ,guile-assertion-failure-converter)
  265. (regular-expression-syntax . ,guile-assertion-failure-converter)
  266. (program-error . ,guile-assertion-failure-converter)
  267. (goops-error . ,guile-assertion-failure-converter)
  268. (null-pointer-error . ,guile-assertion-failure-converter)
  269. (system-error . ,guile-system-error-converter)
  270. (host-not-found . ,guile-external-error-converter)
  271. (getaddrinfo-error . ,guile-external-error-converter)
  272. (no-data . ,guile-external-error-converter)
  273. (no-recovery . ,guile-external-error-converter)
  274. (try-again . ,guile-external-error-converter)
  275. (stack-overflow . ,guile-implementation-restriction-converter)
  276. (numerical-overflow . ,guile-implementation-restriction-converter)
  277. (memory-allocation-error . ,guile-implementation-restriction-converter)))
  278. (define (set-guile-exception-converter! key proc)
  279. (set! guile-exception-converters
  280. (acons key proc guile-exception-converters)))
  281. ;; Override core definition.
  282. (set! make-exception-from-throw convert-guile-exception)