123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- ;;;;; Foundational procedure definitions:
- ;;;;; has-ancestors? get-ancestors get-handler has-handler? resend send
- (define (has-ancestors? obj)
- (let ((result (assq 'ancestors obj)))
- (and result
- (cdr result)
- (procedure? (cdr result))
- (let ((ancestors ((cdr result) obj)))
- (and (list? ancestors)
- (not (null? ancestors)))))))
- (define (get-ancestors obj)
- (if (has-ancestors? obj)
- ((cdr (assq 'ancestors obj)) obj)
- '()))
- (define (get-handler del msg)
- (and (list? del)
- (let ((handler (assq msg del)))
- (if handler
- handler
- (and (has-ancestors? del)
- (let loop ((ancestors (get-ancestors del)))
- (if (null? ancestors)
- #f
- (if (get-handler (car ancestors) msg)
- (get-handler (car ancestors) msg)
- (loop (cdr ancestors))))))))))
- (define (has-handler? obj msg)
- (if (get-handler obj msg) #t #f))
- (define (resend obj del msg . args)
- (let ((handler (get-handler del msg)))
- (if handler
- (if (or (procedure? (cdr handler))
- (not (null? args)))
- (apply (cdr handler) obj args)
- (cdr handler))
- ;; allow overriding behavior with message-not-understood
- (let ((not-understood-handler (get-handler del 'message-not-understood)))
- (if (and not-understood-handler (procedure? (cdr not-understood-handler)))
- ((cdr not-understood-handler) obj msg args)
- (error "send" "Message not understood" msg))))))
- (define (send obj msg . args)
- (apply resend obj obj msg args))
- ;;;;; Syntax for defining operations:
- ;;;;; define-predicate define-operation
- (define-syntax define-predicate
- (syntax-rules ()
- ((_ name)
- (define (name obj)
- (and (list? obj)
- (has-handler? obj 'name)
- (send obj 'name))))))
- (define-syntax define-operation
- (syntax-rules ()
- ((_ (name obj args ...))
- (define (name obj args ...)
- (send obj 'name args ...)))
- ((_ (name obj args ...) default-behavior ...)
- (define (name obj args ...)
- (if (has-handler? obj 'name)
- (send obj 'name args ...)
- (let ()
- default-behavior ...))))
- ((_ (name obj . args))
- (define (name obj . args)
- (apply send obj 'name args)))
- ((_ (name obj . args) default-behavior ...)
- (define (name obj . args)
- (if (has-handler? obj 'name)
- (apply send obj 'name args)
- (let ()
- default-behavior ...))))))
- ;;;;; Syntax for creating objects and resending:
- ;;;;; object object-with-ancestors operate-as
- (define-syntax object
- (syntax-rules ()
- ((_) '())
- ((_ ((msg self args ...) behavior ...) rest ...)
- (cons
- (cons 'msg
- (lambda (self args ...)
- behavior ...))
- (object rest ...)))
- ((_ ((msg self . args) behavior ...) rest ...)
- (cons
- (cons 'msg
- (lambda (self . args)
- behavior ...))
- (object rest ...)))))
- (define-syntax object-with-ancestors
- (syntax-rules ()
- ((_ ((ancestor1 init1) ...) rest ...)
- (let ((ancestor1 init1) ...)
- (cons
- (cons 'ancestors
- (lambda (self)
- (list ancestor1 ...)))
- (object rest ...))))))
- (define-syntax operate-as
- (syntax-rules ()
- ((_ del msg obj args ...)
- (resend obj del msg args ...))))
- ;;;;; Other helpful operations
- ;;;;; protocol simplify-object
- (define (remove-dupes l)
- ;; remove duplicate keys from a list
- ;; not exported, helper for protocol
- (let loop ((result '())
- (next l))
- (if (null? next)
- (reverse result)
- (loop (if (memq (car next) result)
- result
- (cons (car next) result))
- (cdr next)))))
- (define (expand-ancestors obj)
- ;; append an object with its ancestors
- ;; not exported, helper for protocol
- (append
- obj
- (apply append (map expand-ancestors (get-ancestors obj)))))
- (define protocol
- (case-lambda
- ((obj)
- (remove-dupes (map car (expand-ancestors obj))))
- ((obj msg)
- (and (has-handler? obj msg)
- (cdr (get-handler obj msg))))))
- (define (simplify-object obj keys)
- ;; sends each key to the object, returning an alist
- ;; with the resulting values
- (map (lambda (key)
- (cons key (send obj key)))
- keys))
|