📄 goops.scm
字号:
(let ((can-go-in-now (filter (lambda (x) (every (lambda (constraint) (or (not (eq? (cadr constraint) x)) (memq (car constraint) result))) constraints)) elements))) (if (null? can-go-in-now) (goops-error "top-sort: Invalid constraints") (let ((choice (if (null? (cdr can-go-in-now)) (car can-go-in-now) (tie-breaker result can-go-in-now)))) (loop (filter (lambda (x) (not (eq? x choice))) elements) constraints (append result (list choice)))))))))(define (std-tie-breaker get-supers) (lambda (partial-cpl min-elts) (let loop ((pcpl (reverse partial-cpl))) (let ((current-elt (car pcpl))) (let ((ds-of-ce (get-supers current-elt))) (let ((common (filter (lambda (x) (memq x ds-of-ce)) min-elts))) (if (null? common) (if (null? (cdr pcpl)) (goops-error "std-tie-breaker: Nothing valid") (loop (cdr pcpl))) (car common))))))))(define (build-transitive-closure get-follow-ons) (lambda (x) (let track ((result '()) (pending (list x))) (if (null? pending) result (let ((next (car pending))) (if (memq next result) (track result (cdr pending)) (track (cons next result) (append (get-follow-ons next) (cdr pending)))))))))(define (build-constraints get-follow-ons) (lambda (x) (let loop ((elements ((build-transitive-closure get-follow-ons) x)) (this-one '()) (result '())) (if (or (null? this-one) (null? (cdr this-one))) (if (null? elements) result (loop (cdr elements) (cons (car elements) (get-follow-ons (car elements))) result)) (loop elements (cdr this-one) (cons (list (car this-one) (cadr this-one)) result))))));;; compute-get-n-set;;;(define-method (compute-get-n-set (class <class>) s) (case (slot-definition-allocation s) ((#:instance) ;; Instance slot ;; get-n-set is just its offset (let ((already-allocated (slot-ref class 'nfields))) (slot-set! class 'nfields (+ already-allocated 1)) already-allocated)) ((#:class) ;; Class slot ;; Class-slots accessors are implemented as 2 closures around ;; a Scheme variable. As instance slots, class slots must be ;; unbound at init time. (let ((name (slot-definition-name s))) (if (memq name (map slot-definition-name (class-direct-slots class))) ;; This slot is direct; create a new shared variable (make-closure-variable class) ;; Slot is inherited. Find its definition in superclass (let loop ((l (cdr (class-precedence-list class)))) (let ((r (assoc name (slot-ref (car l) 'getters-n-setters)))) (if r (cddr r) (loop (cdr l)))))))) ((#:each-subclass) ;; slot shared by instances of direct subclass. ;; (Thomas Buerger, April 1998) (make-closure-variable class)) ((#:virtual) ;; No allocation ;; slot-ref and slot-set! function must be given by the user (let ((get (get-keyword #:slot-ref (slot-definition-options s) #f)) (set (get-keyword #:slot-set! (slot-definition-options s) #f)) (env (class-environment class))) (if (not (and get set)) (goops-error "You must supply a :slot-ref and a :slot-set! in ~S" s)) (list get set))) (else (next-method))))(define (make-closure-variable class) (let ((shared-variable (make-unbound))) (list (lambda (o) shared-variable) (lambda (o v) (set! shared-variable v)))))(define-method (compute-get-n-set (o <object>) s) (goops-error "Allocation \"~S\" is unknown" (slot-definition-allocation s)))(define-method (compute-slots (class <class>)) (%compute-slots class));;;;;; {Initialize};;;(define-method (initialize (object <object>) initargs) (%initialize-object object initargs))(define-method (initialize (class <class>) initargs) (next-method) (let ((dslots (get-keyword #:slots initargs '())) (supers (get-keyword #:dsupers initargs '())) (env (get-keyword #:environment initargs (top-level-env)))) (slot-set! class 'name (get-keyword #:name initargs '???)) (slot-set! class 'direct-supers supers) (slot-set! class 'direct-slots dslots) (slot-set! class 'direct-subclasses '()) (slot-set! class 'direct-methods '()) (slot-set! class 'cpl (compute-cpl class)) (slot-set! class 'redefined #f) (slot-set! class 'environment env) (let ((slots (compute-slots class))) (slot-set! class 'slots slots) (slot-set! class 'nfields 0) (slot-set! class 'getters-n-setters (compute-getters-n-setters class slots env)) ;; Build getters - setters - accessors (compute-slot-accessors class slots env)) ;; Update the "direct-subclasses" of each inherited classes (for-each (lambda (x) (slot-set! x 'direct-subclasses (cons class (slot-ref x 'direct-subclasses)))) supers) ;; Support for the underlying structs: ;; Inherit class flags (invisible on scheme level) from supers (%inherit-magic! class supers) ;; Set the layout slot (%prep-layout! class)))(define (initialize-object-procedure object initargs) (let ((proc (get-keyword #:procedure initargs #f))) (cond ((not proc)) ((pair? proc) (apply set-object-procedure! object proc)) ((valid-object-procedure? proc) (set-object-procedure! object proc)) (else (set-object-procedure! object (lambda args (apply proc args)))))))(define-method (initialize (class <operator-class>) initargs) (next-method) (initialize-object-procedure class initargs))(define-method (initialize (owsc <operator-with-setter-class>) initargs) (next-method) (%set-object-setter! owsc (get-keyword #:setter initargs #f)))(define-method (initialize (entity <entity>) initargs) (next-method) (initialize-object-procedure entity initargs))(define-method (initialize (ews <entity-with-setter>) initargs) (next-method) (%set-object-setter! ews (get-keyword #:setter initargs #f)))(define-method (initialize (generic <generic>) initargs) (let ((previous-definition (get-keyword #:default initargs #f)) (name (get-keyword #:name initargs #f))) (next-method) (slot-set! generic 'methods (if (is-a? previous-definition <procedure>) (list (make <method> #:specializers <top> #:procedure (lambda l (apply previous-definition l)))) '())) (if name (set-procedure-property! generic 'name name)) ))(define dummy-procedure (lambda args *unspecified*))(define-method (initialize (method <method>) initargs) (next-method) (slot-set! method 'generic-function (get-keyword #:generic-function initargs #f)) (slot-set! method 'specializers (get-keyword #:specializers initargs '())) (slot-set! method 'procedure (get-keyword #:procedure initargs dummy-procedure)) (slot-set! method 'code-table '()))(define-method (initialize (obj <foreign-object>) initargs));;;;;; {Change-class};;;(define (change-object-class old-instance old-class new-class) (let ((new-instance (allocate-instance new-class '()))) ;; Initalize the slot of the new instance (for-each (lambda (slot) (if (and (slot-exists-using-class? old-class old-instance slot) (eq? (slot-definition-allocation (class-slot-definition old-class slot)) #:instance) (slot-bound-using-class? old-class old-instance slot)) ;; Slot was present and allocated in old instance; copy it (slot-set-using-class! new-class new-instance slot (slot-ref-using-class old-class old-instance slot)) ;; slot was absent; initialize it with its default value (let ((init (slot-init-function new-class slot))) (if init (slot-set-using-class! new-class new-instance slot (apply init '())))))) (map slot-definition-name (class-slots new-class))) ;; Exchange old and new instance in place to keep pointers valid (%modify-instance old-instance new-instance) ;; Allow class specific updates of instances (which now are swapped) (update-instance-for-different-class new-instance old-instance) old-instance))(define-method (update-instance-for-different-class (old-instance <object>) (new-instance <object>)) ;;not really important what we do, we just need a default method new-instance)(define-method (change-class (old-instance <object>) (new-class <class>)) (change-object-class old-instance (class-of old-instance) new-class));;;;;; {make};;;;;; A new definition which overwrites the previous one which was built-in;;;(define-method (allocate-instance (class <class>) initargs) (%allocate-instance class initargs))(define-method (make-instance (class <class>) . initargs) (let ((instance (allocate-instance class initargs))) (initialize instance initargs) instance))(define make make-instance);;;;;; {apply-generic};;;;;; Protocol for calling standard generic functions. This protocol is;;; not used for real <generic> functions (in this case we use a;;; completely C hard-coded protocol). Apply-generic is used by;;; goops for calls to subclasses of <generic> and <generic-with-setter>.;;; The code below is similar to the first MOP described in AMOP. In;;; particular, it doesn't used the currified approach to gf;;; call. There are 2 reasons for that:;;; - the protocol below is exposed to mimic completely the one written in C;;; - the currified protocol would be imho inefficient in C.;;;(define-method (apply-generic (gf <generic>) args) (if (null? (slot-ref gf 'methods)) (no-method gf args)) (let ((methods (compute-applicable-methods gf args))) (if methods (apply-methods gf (sort-applicable-methods gf methods args) args) (no-applicable-method gf args))));; compute-applicable-methods is bound to %compute-applicable-methods.;; *fixme* use let(define %%compute-applicable-methods (make <generic> #:name 'compute-applicable-methods))(define-method (%%compute-applicable-methods (gf <generic>) args) (%compute-applicable-methods gf args))(set! compute-applicable-methods %%compute-applicable-methods)(define-method (sort-applicable-methods (gf <generic>) methods args) (let ((targs (map class-of args))) (sort methods (lambda (m1 m2) (method-more-specific? m1 m2 targs)))))(define-method (method-more-specific? (m1 <method>) (m2 <method>) targs) (%method-more-specific? m1 m2 targs))(define-method (apply-method (gf <generic>) methods build-next args) (apply (method-procedure (car methods)) (build-next (cdr methods) args) args))(define-method (apply-methods (gf <generic>) (l <list>) args) (letrec ((next (lambda (procs args) (lambda new-args (let ((a (if (null? new-args) args new-args))) (if (null? procs) (no-next-method gf a) (apply-method gf procs next a))))))) (apply-method gf l next args)));; We don't want the following procedure to turn up in backtraces:(for-each (lambda (proc) (set-procedure-property! proc 'system-procedure #t)) (list slot-unbound slot-missing no-next-method no-applicable-method no-method ));;;;;; {<composite-metaclass> and <active-metaclass>};;;;(autoload "active-slot" <active-metaclass>);(autoload "composite-slot" <composite-metaclass>);(export <composite-metaclass> <active-metaclass>);;;;;; {Tools};;;;; list2set;;;; duplicate the standard list->set function but using eq instead of;; eqv which really sucks a lot, uselessly here;;(define (list2set l) (let loop ((l l) (res '())) (cond ((null? l) res) ((memq (car l) res) (loop (cdr l) res)) (else (loop (cdr l) (cons (car l) res))))))(define (class-subclasses c) (letrec ((allsubs (lambda (c) (cons c (mapappend allsubs (class-direct-subclasses c)))))) (list2set (cdr (allsubs c)))))(define (class-methods c) (list2set (mapappend class-direct-methods (cons c (class-subclasses c)))));;;;;; {Final initialization};;;;; Tell C code that the main bulk of Goops has been loaded(%goops-loaded)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -