123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
- ;; This is an implementation of SRFI 35, together with some conversion
- ;; machinery to dock to the primitive condition system in SIMPLE-CONDITIONS.
- (define-record-type condition-type :condition-type
- (really-make-condition-type name supertype fields all-fields)
- condition-type?
- (name condition-type-name)
- (supertype condition-type-supertype)
- (fields condition-type-fields)
- (all-fields condition-type-all-fields))
- (define-record-discloser :condition-type
- (lambda (r)
- (list 'condition-type
- (condition-type-name r))))
- (define (make-condition-type name supertype fields)
- (if (not (symbol? name))
- (call-error "name is not a symbol"
- make-condition-type
- name))
- (if (not (condition-type? supertype))
- (call-error "supertype is not a condition type"
- make-condition-type
- supertype))
- (if (elements-in-common? (condition-type-all-fields supertype)
- fields)
- (call-error "duplicate field name"
- make-condition-type
- fields (condition-type-all-fields supertype)))
- (really-make-condition-type name
- supertype
- fields
- (append (condition-type-all-fields supertype)
- fields)))
- (define-syntax define-condition-type
- (syntax-rules ()
- ((define-condition-type ?name ?supertype ?predicate
- (?field1 ?accessor1) ...)
- (begin
- (define ?name
- (make-condition-type '?name
- ?supertype
- '(?field1 ...)))
- (define (?predicate thing)
- (and (condition? thing)
- (condition-has-type? thing ?name)))
- (define (?accessor1 condition)
- (condition-ref (extract-condition condition ?name)
- '?field1))
- ...))))
- (define (condition-subtype? subtype supertype)
- (let recur ((subtype subtype))
- (cond ((not subtype) #f)
- ((eq? subtype supertype) #t)
- (else
- (recur (condition-type-supertype subtype))))))
- (define (condition-type-field-supertype condition-type field)
- (let loop ((condition-type condition-type))
- (cond ((not condition-type) #f)
- ((memq field (condition-type-fields condition-type))
- condition-type)
- (else
- (loop (condition-type-supertype condition-type))))))
- ; The type-field-alist is of the form
- ; ((<type> (<field-name> . <value>) ...) ...)
- (define-record-type condition :condition
- (really-really-make-condition type-field-alist)
- condition?
- (type-field-alist condition-type-field-alist))
- (define-record-discloser :condition
- (lambda (r)
- (cons 'condition
- (condition-type-field-alist r))))
- ;; pairs of (type . discloser)
- ;; Each discloser consumes the entire condition object
- ;; and returns a list of irritants
- (define *primitive-condition-disclose-alist* '())
- (define (define-primitive-condition-discloser type discloser)
- (set! *primitive-condition-disclose-alist*
- (cons (cons type discloser) *primitive-condition-disclose-alist*)))
- (define (disclose-primitive-condition type alist condition)
- (let loop ((discloser-alist *primitive-condition-disclose-alist*))
- (cond
- ((null? discloser-alist)
- (list (cons (condition-type-name type) alist)))
- ((eq? type (caar discloser-alist))
- ((cdar discloser-alist) condition))
- (else
- (loop (cdr discloser-alist))))))
- ;; This is messy because it generates output for humns
- (define-method &disclose-condition ((c :condition))
- (let* ((type-field-alist (condition-type-field-alist c))
- (simple (assq &simple-condition type-field-alist)))
- (if (and simple
- (pair? type-field-alist)
- (null? (cdr type-field-alist)))
- ;; rare case: all we have is the converted simple condition
- (cons (simple-condition-type c)
- (simple-condition-stuff c))
- (let ((type-symbol
- (cond
- ((error? c) 'error)
- ((warning? c) 'warning)
- ((bug? c) 'bug)
- (else 'condition)))
- (relevant
- (apply append
- (filter-map (lambda (pair)
- (let ((type (car pair)))
- (cond
- ((or (eq? &message type)
- (eq? &simple-condition type)
- (eq? &irritants type))
- #f)
- (else
- (disclose-primitive-condition (car pair) (cdr pair) c)))))
- (condition-type-field-alist c)))))
- `(,type-symbol
- ,@(if (message-condition? c)
- (list (condition-message c))
- '())
- ,@(if (irritants? c)
- (condition-irritants c)
- '())
- ,@relevant)))))
- (define (really-make-condition type-field-alist)
- (for-each (lambda (pair)
- (let ((type (car pair))
- (alist (cdr pair)))
- (if (not (list-set-eq? (condition-type-all-fields type)
- (map car alist)))
- (call-error "condition fields don't match condition type"
- really-make-condition
- (map car alist)
- (condition-type-all-fields type)
- type-field-alist))))
- type-field-alist)
- (really-really-make-condition type-field-alist))
- (define (make-condition type . field-plist)
- (let ((alist (let label ((plist field-plist))
- (if (null? plist)
- '()
- (cons (cons (car plist)
- (cadr plist))
- (label (cddr plist)))))))
- (if (not (list-set-eq? (condition-type-all-fields type)
- (map car alist)))
- (apply call-error "condition fields don't match condition type"
- make-condition
- type field-plist))
- (really-make-condition (list (cons type alist)))))
- (define (condition-has-type? condition type)
- (any? (lambda (has-type)
- (condition-subtype? has-type type))
- (condition-types condition)))
- (define (condition-ref condition field)
- (type-field-alist-ref (condition-type-field-alist condition)
- field))
- (define (type-field-alist-ref the-type-field-alist field)
- (let loop ((type-field-alist the-type-field-alist))
- (cond ((null? type-field-alist)
- (call-error "field not found"
- type-field-alist-ref
- field the-type-field-alist))
- ((assq field (cdr (car type-field-alist)))
- => cdr)
- (else
- (loop (cdr type-field-alist))))))
- (define (make-compound-condition condition-1 . conditions)
- (really-make-condition
- (apply append (map condition-type-field-alist
- (cons condition-1 conditions)))))
- (define (extract-condition condition type)
- (let ((entry (first (lambda (entry)
- (condition-subtype? (car entry) type))
- (condition-type-field-alist condition))))
- (if (not entry)
- (call-error "invalid condition type"
- extract-condition
- condition type))
- (really-make-condition
- (list (cons type
- (map (lambda (field)
- (assq field (cdr entry)))
- (condition-type-all-fields type)))))))
- (define-syntax condition
- (syntax-rules ()
- ((condition (?type1 (?field1 ?value1) ...) ...)
- (type-field-alist->condition
- (list
- (cons ?type1
- (list (cons '?field1 ?value1) ...))
- ...)))))
- (define (type-field-alist->condition type-field-alist)
- (really-make-condition
- (map (lambda (entry)
- (let* ((type (car entry))
- (all-fields (condition-type-all-fields type)))
- (if (not (list-set<=? (map car (cdr entry)) all-fields))
- (call-error "invalid field or fields"
- type-field-alist->condition
- (map car (cdr entry))
- type
- all-fields))
- (cons type
- (map (lambda (field)
- (or (assq field (cdr entry))
- (cons field
- (type-field-alist-ref type-field-alist field))))
- all-fields))))
- type-field-alist)))
- (define (condition-types condition)
- (map car (condition-type-field-alist condition)))
- (define (check-condition-type-field-alist the-type-field-alist)
- (let loop ((type-field-alist the-type-field-alist))
- (if (not (null? type-field-alist))
- (let* ((entry (car type-field-alist))
- (type (car entry))
- (field-alist (cdr entry))
- (fields (map car field-alist))
- (all-fields (condition-type-all-fields type)))
- (for-each (lambda (missing-field)
- (let ((supertype
- (condition-type-field-supertype type missing-field)))
- (if (not
- (any? (lambda (entry)
- (let ((type (car entry)))
- (condition-subtype? type supertype)))
- the-type-field-alist))
- (call-error "missing field in condition construction"
- check-condition-type-field-alist
- type
- missing-field
- the-type-field-alist))))
- (list-set-difference all-fields fields))
- (loop (cdr type-field-alist))))))
- ;; Utilities, defined locally to avoid having to load SRFI 1 or
- ;; BIG-UTIL into the image.
- ;; (These need to come before the standard condition types below.)
- (define (elements-in-common? list-1 list-2)
- (any? (lambda (element-1)
- (memq element-1 list-2))
- list-1))
- (define (list-set<=? list-1 list-2)
- (every? (lambda (element-1)
- (memq element-1 list-2))
- list-1))
- (define (list-set-eq? list-1 list-2)
- (and (list-set<=? list-1 list-2)
- (list-set<=? list-2 list-1)))
- (define (list-set-difference list-1 list-2)
- (filter (lambda (element-1)
- (not (memq element-1 list-2)))
- list-1))
- (define (filter-map f l)
- (let loop ((l l) (r '()))
- (cond ((null? l)
- (reverse r))
- ((f (car l))
- => (lambda (x)
- (loop (cdr l) (cons x r))))
- (else
- (loop (cdr l) r)))))
- (define (first pred list)
- (let loop ((list list))
- (cond ((null? list)
- #f)
- ((pred (car list))
- (car list))
- (else
- (loop (cdr list))))))
- (define (any? proc list)
- (let loop ((list list))
- (cond ((null? list)
- #f)
- ((proc (car list))
- #t)
- (else
- (loop (cdr list))))))
- (define (every? pred list)
- (let loop ((list list))
- (cond ((null? list)
- #t)
- ((pred (car list))
- (loop (cdr list)))
- (else
- #f))))
- (define (filter pred l)
- (let loop ((l l) (r '()))
- (cond ((null? l)
- (reverse r))
- ((pred (car l))
- (loop (cdr l) (cons (car l) r)))
- (else
- (loop (cdr l) r)))))
- ;; Standard condition types
- (define &condition (really-make-condition-type '&condition
- #f
- '()
- '()))
- (define-condition-type &message &condition
- message-condition?
- (message condition-message))
- (define-condition-type &serious &condition
- serious-condition?)
- (define-condition-type &error &serious
- error?)
- ;; Beyond SRFI 35
- (define-condition-type &bug &serious
- bug?)
- ;; High-level versions of what's in SIMPLE-CONDITIONS
- (define-condition-type &irritants &condition
- irritants?
- (values condition-irritants))
- (define-condition-type &call-error &bug
- call-error?
- (proc call-error-proc)
- (args call-error-args))
- (define-primitive-condition-discloser &call-error
- (lambda (c)
- (list 'call-error:
- (cons (call-error-proc c)
- (call-error-args c)))))
- (define-condition-type &vm-exception &error
- vm-exception?
- (opcode vm-exception-opcode)
- (reason vm-exception-reason)
- (arguments vm-exception-arguments))
- (define-primitive-condition-discloser &vm-exception
- (lambda (c)
- (cddr ; car is always ERROR, cadr is always the message
- (disclose-vm-condition (vm-exception-opcode c)
- (vm-exception-reason c)
- (vm-exception-arguments c)))))
- (define-condition-type &warning &condition
- warning?)
- (define-condition-type ¬e &condition
- note?)
- (define-condition-type &syntax-error &warning
- syntax-error?)
- ;; This doesn't really belong here
- (define-condition-type &interrupt &condition
- interrupt?
- (type interrupt-type))
- (define-primitive-condition-discloser &interrupt
- (lambda (c)
- (list
- (list '&interrupt
- (enumerand->name (interrupt-type c) interrupt)))))
- (define-condition-type &decoding-error &error
- decoding-error?
- (encoding-name decoding-error-encoding-name))
- (define-primitive-condition-discloser &decoding-error
- (lambda (c)
- (list
- (list '&decoding-error
- (decoding-error-encoding-name c)))))
- ;; This is for backwards compatibility and shouldn't be used by application code
- (define-condition-type &simple-condition &condition
- simple-condition?
- (type simple-condition-type)
- (stuff simple-condition-stuff))
|