condition.scm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ;; This is an implementation of SRFI 35, together with some conversion
  3. ;; machinery to dock to the primitive condition system in SIMPLE-CONDITIONS.
  4. (define-record-type condition-type :condition-type
  5. (really-make-condition-type name supertype fields all-fields)
  6. condition-type?
  7. (name condition-type-name)
  8. (supertype condition-type-supertype)
  9. (fields condition-type-fields)
  10. (all-fields condition-type-all-fields))
  11. (define-record-discloser :condition-type
  12. (lambda (r)
  13. (list 'condition-type
  14. (condition-type-name r))))
  15. (define (make-condition-type name supertype fields)
  16. (if (not (symbol? name))
  17. (call-error "name is not a symbol"
  18. make-condition-type
  19. name))
  20. (if (not (condition-type? supertype))
  21. (call-error "supertype is not a condition type"
  22. make-condition-type
  23. supertype))
  24. (if (elements-in-common? (condition-type-all-fields supertype)
  25. fields)
  26. (call-error "duplicate field name"
  27. make-condition-type
  28. fields (condition-type-all-fields supertype)))
  29. (really-make-condition-type name
  30. supertype
  31. fields
  32. (append (condition-type-all-fields supertype)
  33. fields)))
  34. (define-syntax define-condition-type
  35. (syntax-rules ()
  36. ((define-condition-type ?name ?supertype ?predicate
  37. (?field1 ?accessor1) ...)
  38. (begin
  39. (define ?name
  40. (make-condition-type '?name
  41. ?supertype
  42. '(?field1 ...)))
  43. (define (?predicate thing)
  44. (and (condition? thing)
  45. (condition-has-type? thing ?name)))
  46. (define (?accessor1 condition)
  47. (condition-ref (extract-condition condition ?name)
  48. '?field1))
  49. ...))))
  50. (define (condition-subtype? subtype supertype)
  51. (let recur ((subtype subtype))
  52. (cond ((not subtype) #f)
  53. ((eq? subtype supertype) #t)
  54. (else
  55. (recur (condition-type-supertype subtype))))))
  56. (define (condition-type-field-supertype condition-type field)
  57. (let loop ((condition-type condition-type))
  58. (cond ((not condition-type) #f)
  59. ((memq field (condition-type-fields condition-type))
  60. condition-type)
  61. (else
  62. (loop (condition-type-supertype condition-type))))))
  63. ; The type-field-alist is of the form
  64. ; ((<type> (<field-name> . <value>) ...) ...)
  65. (define-record-type condition :condition
  66. (really-really-make-condition type-field-alist)
  67. condition?
  68. (type-field-alist condition-type-field-alist))
  69. (define-record-discloser :condition
  70. (lambda (r)
  71. (cons 'condition
  72. (condition-type-field-alist r))))
  73. ;; pairs of (type . discloser)
  74. ;; Each discloser consumes the entire condition object
  75. ;; and returns a list of irritants
  76. (define *primitive-condition-disclose-alist* '())
  77. (define (define-primitive-condition-discloser type discloser)
  78. (set! *primitive-condition-disclose-alist*
  79. (cons (cons type discloser) *primitive-condition-disclose-alist*)))
  80. (define (disclose-primitive-condition type alist condition)
  81. (let loop ((discloser-alist *primitive-condition-disclose-alist*))
  82. (cond
  83. ((null? discloser-alist)
  84. (list (cons (condition-type-name type) alist)))
  85. ((eq? type (caar discloser-alist))
  86. ((cdar discloser-alist) condition))
  87. (else
  88. (loop (cdr discloser-alist))))))
  89. ;; This is messy because it generates output for humns
  90. (define-method &disclose-condition ((c :condition))
  91. (let* ((type-field-alist (condition-type-field-alist c))
  92. (simple (assq &simple-condition type-field-alist)))
  93. (if (and simple
  94. (pair? type-field-alist)
  95. (null? (cdr type-field-alist)))
  96. ;; rare case: all we have is the converted simple condition
  97. (cons (simple-condition-type c)
  98. (simple-condition-stuff c))
  99. (let ((type-symbol
  100. (cond
  101. ((error? c) 'error)
  102. ((warning? c) 'warning)
  103. ((bug? c) 'bug)
  104. (else 'condition)))
  105. (relevant
  106. (apply append
  107. (filter-map (lambda (pair)
  108. (let ((type (car pair)))
  109. (cond
  110. ((or (eq? &message type)
  111. (eq? &simple-condition type)
  112. (eq? &irritants type))
  113. #f)
  114. (else
  115. (disclose-primitive-condition (car pair) (cdr pair) c)))))
  116. (condition-type-field-alist c)))))
  117. `(,type-symbol
  118. ,@(if (message-condition? c)
  119. (list (condition-message c))
  120. '())
  121. ,@(if (irritants? c)
  122. (condition-irritants c)
  123. '())
  124. ,@relevant)))))
  125. (define (really-make-condition type-field-alist)
  126. (for-each (lambda (pair)
  127. (let ((type (car pair))
  128. (alist (cdr pair)))
  129. (if (not (list-set-eq? (condition-type-all-fields type)
  130. (map car alist)))
  131. (call-error "condition fields don't match condition type"
  132. really-make-condition
  133. (map car alist)
  134. (condition-type-all-fields type)
  135. type-field-alist))))
  136. type-field-alist)
  137. (really-really-make-condition type-field-alist))
  138. (define (make-condition type . field-plist)
  139. (let ((alist (let label ((plist field-plist))
  140. (if (null? plist)
  141. '()
  142. (cons (cons (car plist)
  143. (cadr plist))
  144. (label (cddr plist)))))))
  145. (if (not (list-set-eq? (condition-type-all-fields type)
  146. (map car alist)))
  147. (apply call-error "condition fields don't match condition type"
  148. make-condition
  149. type field-plist))
  150. (really-make-condition (list (cons type alist)))))
  151. (define (condition-has-type? condition type)
  152. (any? (lambda (has-type)
  153. (condition-subtype? has-type type))
  154. (condition-types condition)))
  155. (define (condition-ref condition field)
  156. (type-field-alist-ref (condition-type-field-alist condition)
  157. field))
  158. (define (type-field-alist-ref the-type-field-alist field)
  159. (let loop ((type-field-alist the-type-field-alist))
  160. (cond ((null? type-field-alist)
  161. (call-error "field not found"
  162. type-field-alist-ref
  163. field the-type-field-alist))
  164. ((assq field (cdr (car type-field-alist)))
  165. => cdr)
  166. (else
  167. (loop (cdr type-field-alist))))))
  168. (define (make-compound-condition condition-1 . conditions)
  169. (really-make-condition
  170. (apply append (map condition-type-field-alist
  171. (cons condition-1 conditions)))))
  172. (define (extract-condition condition type)
  173. (let ((entry (first (lambda (entry)
  174. (condition-subtype? (car entry) type))
  175. (condition-type-field-alist condition))))
  176. (if (not entry)
  177. (call-error "invalid condition type"
  178. extract-condition
  179. condition type))
  180. (really-make-condition
  181. (list (cons type
  182. (map (lambda (field)
  183. (assq field (cdr entry)))
  184. (condition-type-all-fields type)))))))
  185. (define-syntax condition
  186. (syntax-rules ()
  187. ((condition (?type1 (?field1 ?value1) ...) ...)
  188. (type-field-alist->condition
  189. (list
  190. (cons ?type1
  191. (list (cons '?field1 ?value1) ...))
  192. ...)))))
  193. (define (type-field-alist->condition type-field-alist)
  194. (really-make-condition
  195. (map (lambda (entry)
  196. (let* ((type (car entry))
  197. (all-fields (condition-type-all-fields type)))
  198. (if (not (list-set<=? (map car (cdr entry)) all-fields))
  199. (call-error "invalid field or fields"
  200. type-field-alist->condition
  201. (map car (cdr entry))
  202. type
  203. all-fields))
  204. (cons type
  205. (map (lambda (field)
  206. (or (assq field (cdr entry))
  207. (cons field
  208. (type-field-alist-ref type-field-alist field))))
  209. all-fields))))
  210. type-field-alist)))
  211. (define (condition-types condition)
  212. (map car (condition-type-field-alist condition)))
  213. (define (check-condition-type-field-alist the-type-field-alist)
  214. (let loop ((type-field-alist the-type-field-alist))
  215. (if (not (null? type-field-alist))
  216. (let* ((entry (car type-field-alist))
  217. (type (car entry))
  218. (field-alist (cdr entry))
  219. (fields (map car field-alist))
  220. (all-fields (condition-type-all-fields type)))
  221. (for-each (lambda (missing-field)
  222. (let ((supertype
  223. (condition-type-field-supertype type missing-field)))
  224. (if (not
  225. (any? (lambda (entry)
  226. (let ((type (car entry)))
  227. (condition-subtype? type supertype)))
  228. the-type-field-alist))
  229. (call-error "missing field in condition construction"
  230. check-condition-type-field-alist
  231. type
  232. missing-field
  233. the-type-field-alist))))
  234. (list-set-difference all-fields fields))
  235. (loop (cdr type-field-alist))))))
  236. ;; Utilities, defined locally to avoid having to load SRFI 1 or
  237. ;; BIG-UTIL into the image.
  238. ;; (These need to come before the standard condition types below.)
  239. (define (elements-in-common? list-1 list-2)
  240. (any? (lambda (element-1)
  241. (memq element-1 list-2))
  242. list-1))
  243. (define (list-set<=? list-1 list-2)
  244. (every? (lambda (element-1)
  245. (memq element-1 list-2))
  246. list-1))
  247. (define (list-set-eq? list-1 list-2)
  248. (and (list-set<=? list-1 list-2)
  249. (list-set<=? list-2 list-1)))
  250. (define (list-set-difference list-1 list-2)
  251. (filter (lambda (element-1)
  252. (not (memq element-1 list-2)))
  253. list-1))
  254. (define (filter-map f l)
  255. (let loop ((l l) (r '()))
  256. (cond ((null? l)
  257. (reverse r))
  258. ((f (car l))
  259. => (lambda (x)
  260. (loop (cdr l) (cons x r))))
  261. (else
  262. (loop (cdr l) r)))))
  263. (define (first pred list)
  264. (let loop ((list list))
  265. (cond ((null? list)
  266. #f)
  267. ((pred (car list))
  268. (car list))
  269. (else
  270. (loop (cdr list))))))
  271. (define (any? proc list)
  272. (let loop ((list list))
  273. (cond ((null? list)
  274. #f)
  275. ((proc (car list))
  276. #t)
  277. (else
  278. (loop (cdr list))))))
  279. (define (every? pred list)
  280. (let loop ((list list))
  281. (cond ((null? list)
  282. #t)
  283. ((pred (car list))
  284. (loop (cdr list)))
  285. (else
  286. #f))))
  287. (define (filter pred l)
  288. (let loop ((l l) (r '()))
  289. (cond ((null? l)
  290. (reverse r))
  291. ((pred (car l))
  292. (loop (cdr l) (cons (car l) r)))
  293. (else
  294. (loop (cdr l) r)))))
  295. ;; Standard condition types
  296. (define &condition (really-make-condition-type '&condition
  297. #f
  298. '()
  299. '()))
  300. (define-condition-type &message &condition
  301. message-condition?
  302. (message condition-message))
  303. (define-condition-type &serious &condition
  304. serious-condition?)
  305. (define-condition-type &error &serious
  306. error?)
  307. ;; Beyond SRFI 35
  308. (define-condition-type &bug &serious
  309. bug?)
  310. ;; High-level versions of what's in SIMPLE-CONDITIONS
  311. (define-condition-type &irritants &condition
  312. irritants?
  313. (values condition-irritants))
  314. (define-condition-type &call-error &bug
  315. call-error?
  316. (proc call-error-proc)
  317. (args call-error-args))
  318. (define-primitive-condition-discloser &call-error
  319. (lambda (c)
  320. (list 'call-error:
  321. (cons (call-error-proc c)
  322. (call-error-args c)))))
  323. (define-condition-type &vm-exception &error
  324. vm-exception?
  325. (opcode vm-exception-opcode)
  326. (reason vm-exception-reason)
  327. (arguments vm-exception-arguments))
  328. (define-primitive-condition-discloser &vm-exception
  329. (lambda (c)
  330. (cddr ; car is always ERROR, cadr is always the message
  331. (disclose-vm-condition (vm-exception-opcode c)
  332. (vm-exception-reason c)
  333. (vm-exception-arguments c)))))
  334. (define-condition-type &warning &condition
  335. warning?)
  336. (define-condition-type &note &condition
  337. note?)
  338. (define-condition-type &syntax-error &warning
  339. syntax-error?)
  340. ;; This doesn't really belong here
  341. (define-condition-type &interrupt &condition
  342. interrupt?
  343. (type interrupt-type))
  344. (define-primitive-condition-discloser &interrupt
  345. (lambda (c)
  346. (list
  347. (list '&interrupt
  348. (enumerand->name (interrupt-type c) interrupt)))))
  349. (define-condition-type &decoding-error &error
  350. decoding-error?
  351. (encoding-name decoding-error-encoding-name))
  352. (define-primitive-condition-discloser &decoding-error
  353. (lambda (c)
  354. (list
  355. (list '&decoding-error
  356. (decoding-error-encoding-name c)))))
  357. ;; This is for backwards compatibility and shouldn't be used by application code
  358. (define-condition-type &simple-condition &condition
  359. simple-condition?
  360. (type simple-condition-type)
  361. (stuff simple-condition-stuff))