home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / share / guile / 1.6 / oop / goops.scm
Encoding:
Text File  |  2006-06-19  |  47.4 KB  |  1,566 lines

  1. ;;; installed-scm-file
  2.  
  3. ;;;;     Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
  4. ;;;; 
  5. ;;;; This program is free software; you can redistribute it and/or modify
  6. ;;;; it under the terms of the GNU General Public License as published by
  7. ;;;; the Free Software Foundation; either version 2, or (at your option)
  8. ;;;; any later version.
  9. ;;;; 
  10. ;;;; This program is distributed in the hope that it will be useful,
  11. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. ;;;; GNU General Public License for more details.
  14. ;;;; 
  15. ;;;; You should have received a copy of the GNU General Public License
  16. ;;;; along with this software; see the file COPYING.  If not, write to
  17. ;;;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  18. ;;;; Boston, MA 02110-1301 USA
  19. ;;;;
  20. ;;;; As a special exception, the Free Software Foundation gives permission
  21. ;;;; for additional uses of the text contained in its release of GUILE.
  22. ;;;;
  23. ;;;; The exception is that, if you link the GUILE library with other files
  24. ;;;; to produce an executable, this does not by itself cause the
  25. ;;;; resulting executable to be covered by the GNU General Public License.
  26. ;;;; Your use of that executable is in no way restricted on account of
  27. ;;;; linking the GUILE library code into it.
  28. ;;;;
  29. ;;;; This exception does not however invalidate any other reasons why
  30. ;;;; the executable file might be covered by the GNU General Public License.
  31. ;;;;
  32. ;;;; This exception applies only to the code released by the
  33. ;;;; Free Software Foundation under the name GUILE.  If you copy
  34. ;;;; code from other Free Software Foundation releases into a copy of
  35. ;;;; GUILE, as the General Public License permits, the exception does
  36. ;;;; not apply to the code that you add in this way.  To avoid misleading
  37. ;;;; anyone as to the status of such modified files, you must delete
  38. ;;;; this exception notice from them.
  39. ;;;;
  40. ;;;; If you write modifications of your own for GUILE, it is your choice
  41. ;;;; whether to permit this exception to apply to your modifications.
  42. ;;;; If you do not wish that, delete this exception notice.
  43. ;;;; 
  44.  
  45.  
  46. ;;;; This software is a derivative work of other copyrighted softwares; the
  47. ;;;; copyright notices of these softwares are placed in the file COPYRIGHTS
  48. ;;;;
  49. ;;;; This file is based upon stklos.stk from the STk distribution by
  50. ;;;; Erick Gallesio <eg@unice.fr>.
  51. ;;;;
  52.  
  53. (define-module (oop goops)
  54.   :export-syntax (define-class class
  55.           define-generic define-accessor define-method
  56.           method)
  57.   :export (goops-version is-a?
  58.            ensure-metaclass ensure-metaclass-with-supers
  59.        make-class
  60.        make-generic ensure-generic
  61.        make-accessor ensure-accessor
  62.        make-method add-method!
  63.        object-eqv? object-equal?
  64.        class-slot-ref class-slot-set! slot-unbound slot-missing 
  65.        slot-definition-name  slot-definition-options
  66.        slot-definition-allocation
  67.        slot-definition-getter slot-definition-setter
  68.        slot-definition-accessor
  69.        slot-definition-init-value slot-definition-init-form
  70.        slot-definition-init-thunk slot-definition-init-keyword 
  71.        slot-init-function class-slot-definition
  72.        method-source
  73.        compute-cpl compute-std-cpl compute-get-n-set compute-slots
  74.        compute-getter-method compute-setter-method
  75.        allocate-instance initialize make-instance make
  76.        no-next-method  no-applicable-method no-method
  77.        change-class update-instance-for-different-class
  78.        shallow-clone deep-clone
  79.        class-redefinition
  80.        apply-generic apply-method apply-methods
  81.        compute-applicable-methods %compute-applicable-methods
  82.        method-more-specific? sort-applicable-methods
  83.        class-subclasses class-methods
  84.        goops-error
  85.        min-fixnum max-fixnum
  86.        ;;; *fixme* Should go into goops.c
  87.        instance?  slot-ref-using-class
  88.        slot-set-using-class! slot-bound-using-class?
  89.        slot-exists-using-class? slot-ref slot-set! slot-bound?
  90.        class-name class-direct-supers class-direct-subclasses
  91.        class-direct-methods class-direct-slots class-precedence-list
  92.        class-slots class-environment
  93.        generic-function-name
  94.        generic-function-methods method-generic-function method-specializers
  95.        primitive-generic-generic enable-primitive-generic!
  96.        method-procedure accessor-method-slot-definition
  97.        slot-exists? make find-method get-keyword)
  98.   :re-export (class-of)  ;; from (guile)
  99.   :no-backtrace)
  100.  
  101. ;; First initialize the builtin part of GOOPS
  102. (%init-goops-builtins)
  103.  
  104. ;; Then load the rest of GOOPS
  105. (use-modules (oop goops util)
  106.          (oop goops dispatch)
  107.          (oop goops compile))
  108.  
  109.  
  110. (define min-fixnum (- (expt 2 29)))
  111.  
  112. (define max-fixnum (- (expt 2 29) 1))
  113.  
  114. ;;
  115. ;; goops-error
  116. ;;
  117. (define (goops-error format-string . args)
  118.   (save-stack)
  119.   (scm-error 'goops-error #f format-string args '()))
  120.  
  121. ;;
  122. ;; is-a?
  123. ;;
  124. (define (is-a? obj class)
  125.   (and (memq class (class-precedence-list (class-of obj))) #t))
  126.  
  127.  
  128. ;;;
  129. ;;; {Meta classes}
  130. ;;;
  131.  
  132. (define ensure-metaclass-with-supers
  133.   (let ((table-of-metas '()))
  134.     (lambda (meta-supers)
  135.       (let ((entry (assoc meta-supers table-of-metas)))
  136.     (if entry
  137.         ;; Found a previously created metaclass
  138.         (cdr entry)
  139.         ;; Create a new meta-class which inherit from "meta-supers"
  140.         (let ((new (make <class> #:dsupers meta-supers
  141.                          #:slots   '()
  142.                      #:name   (gensym "metaclass"))))
  143.           (set! table-of-metas (cons (cons meta-supers new) table-of-metas))
  144.           new))))))
  145.  
  146. (define (ensure-metaclass supers env)
  147.   (if (null? supers)
  148.       <class>
  149.       (let* ((all-metas (map (lambda (x) (class-of x)) supers))
  150.          (all-cpls  (apply append
  151.                    (map (lambda (m)
  152.                       (cdr (class-precedence-list m))) 
  153.                     all-metas)))
  154.          (needed-metas '()))
  155.     ;; Find the most specific metaclasses.  The new metaclass will be
  156.     ;; a subclass of these.
  157.     (for-each
  158.      (lambda (meta)
  159.        (if (and (not (member meta all-cpls))
  160.               (not (member meta needed-metas)))
  161.          (set! needed-metas (append needed-metas (list meta)))))
  162.      all-metas)
  163.     ;; Now return a subclass of the metaclasses we found.
  164.     (if (null? (cdr needed-metas))
  165.         (car needed-metas)  ; If there's only one, just use it.
  166.         (ensure-metaclass-with-supers needed-metas)))))
  167.  
  168. ;;;
  169. ;;; {Classes}
  170. ;;;
  171.  
  172. ;;; (define-class NAME (SUPER ...) SLOT-DEFINITION ... OPTION ...)
  173. ;;;
  174. ;;;   SLOT-DEFINITION ::= SLOT-NAME | (SLOT-NAME OPTION ...)
  175. ;;;   OPTION ::= KEYWORD VALUE
  176. ;;;
  177. (define (define-class-pre-definition keyword exp env)
  178.   (case keyword
  179.     ((#:getter #:setter)
  180.      (if (defined? exp env)
  181.      `(define ,exp (ensure-generic ,exp ',exp))
  182.      `(define ,exp (make-generic ',exp))))
  183.     ((#:accessor)
  184.      (if (defined? exp env)
  185.      `(define ,exp (ensure-accessor ,exp ',exp))
  186.      `(define ,exp (make-accessor ',exp))))
  187.     (else #f)))
  188.  
  189. ;;; This code should be implemented in C.
  190. ;;;
  191. (define define-class
  192.   (letrec (;; Some slot options require extra definitions to be made.
  193.        ;; In particular, we want to make sure that the generic
  194.        ;; function objects which represent accessors exist
  195.        ;; before `make-class' tries to add methods to them.
  196.        ;;
  197.        ;; Postpone error handling to class macro.
  198.        ;;
  199.        (pre-definitions
  200.         (lambda (slots env)
  201.           (do ((slots slots (cdr slots))
  202.            (definitions '()
  203.              (if (pair? (car slots))
  204.              (do ((options (cdar slots) (cddr options))
  205.                   (definitions definitions
  206.                 (cond ((not (symbol? (cadr options)))
  207.                        definitions)
  208.                       ((define-class-pre-definition
  209.                      (car options)
  210.                      (cadr options)
  211.                      env)
  212.                        => (lambda (definition)
  213.                         (cons definition definitions)))
  214.                       (else definitions))))
  215.                  ((not (and (pair? options)
  216.                     (pair? (cdr options))))
  217.                   definitions))
  218.              definitions)))
  219.           ((or (not (pair? slots))
  220.                (keyword? (car slots)))
  221.            (reverse definitions)))))
  222.        
  223.        ;; Syntax
  224.        (name cadr)
  225.        (slots cdddr))
  226.     
  227.     (procedure->macro
  228.       (lambda (exp env)
  229.     (cond ((not (top-level-env? env))
  230.            (goops-error "define-class: Only allowed at top level"))
  231.           ((not (and (list? exp) (>= (length exp) 3)))
  232.            (goops-error "missing or extra expression"))
  233.           (else
  234.            (let ((name (name exp)))
  235.          `(begin
  236.             ;; define accessors
  237.             ,@(pre-definitions (slots exp) env)
  238.          
  239.             ,(if (defined? name env)
  240.               
  241.              ;; redefine an old class
  242.              `(define ,name
  243.                 (let ((old ,name)
  244.                   (new (class ,@(cddr exp) #:name ',name)))
  245.                   (if (and (is-a? old <class>)
  246.                        ;; Prevent redefinition of non-objects
  247.                        (memq <object>
  248.                          (class-precedence-list old)))
  249.                   (class-redefinition old new)
  250.                   new)))
  251.               
  252.              ;; define a new class
  253.              `(define ,name
  254.                 (class ,@(cddr exp) #:name ',name)))))))))))
  255.  
  256. (define standard-define-class define-class)
  257.  
  258. ;;; (class (SUPER ...) SLOT-DEFINITION ... OPTION ...)
  259. ;;;
  260. ;;;   SLOT-DEFINITION ::= SLOT-NAME | (SLOT-NAME OPTION ...)
  261. ;;;   OPTION ::= KEYWORD VALUE
  262. ;;;
  263. (define class
  264.   (letrec ((slot-option-keyword car)
  265.        (slot-option-value cadr)
  266.        (process-slot-options
  267.         (lambda (options)
  268.           (let loop ((options options)
  269.              (res '()))
  270.         (cond ((null? options)
  271.                (reverse res))
  272.               ((null? (cdr options))
  273.                (goops-error "malformed slot option list"))
  274.               ((not (keyword? (slot-option-keyword options)))
  275.                (goops-error "malformed slot option list"))
  276.               (else
  277.                (case (slot-option-keyword options)
  278.              ((#:init-form)
  279.               (loop (cddr options)
  280.                 (append (list `(lambda ()
  281.                          ,(slot-option-value options))
  282.                           #:init-thunk
  283.                           (list 'quote
  284.                             (slot-option-value options))
  285.                           #:init-form)
  286.                     res)))
  287.              (else
  288.               (loop (cddr options)
  289.                 (cons (cadr options)
  290.                       (cons (car options)
  291.                         res)))))))))))
  292.     
  293.     (procedure->memoizing-macro
  294.       (let ((supers cadr)
  295.         (slots cddr)
  296.         (options cdddr))
  297.     (lambda (exp env)
  298.       (cond ((not (and (list? exp) (>= (length exp) 2)))
  299.          (goops-error "missing or extra expression"))
  300.         ((not (list? (supers exp)))
  301.          (goops-error "malformed superclass list: ~S" (supers exp)))
  302.         (else
  303.          (let ((slot-defs (cons #f '())))
  304.            (do ((slots (slots exp) (cdr slots))
  305.             (defs slot-defs (cdr defs)))
  306.                ((or (null? slots)
  307.                 (keyword? (car slots)))
  308.             `(make-class
  309.               ;; evaluate super class variables
  310.               (list ,@(supers exp))
  311.               ;; evaluate slot definitions, except the slot name!
  312.               (list ,@(cdr slot-defs))
  313.               ;; evaluate class options
  314.               ,@slots
  315.               ;; place option last in case someone wants to
  316.               ;; pass a different value
  317.               #:environment ',env))
  318.              (set-cdr!
  319.               defs
  320.               (list (if (pair? (car slots))
  321.                 `(list ',(slot-definition-name (car slots))
  322.                        ,@(process-slot-options
  323.                       (slot-definition-options
  324.                        (car slots))))
  325.                 `(list ',(car slots))))))))))))))
  326.  
  327. (define (make-class supers slots . options)
  328.   (let ((env (or (get-keyword #:environment options #f)
  329.          (top-level-env))))
  330.     (let* ((name (get-keyword #:name options (make-unbound)))
  331.        (supers (if (not (or-map (lambda (class)
  332.                       (memq <object>
  333.                         (class-precedence-list class)))
  334.                     supers))
  335.                (append supers (list <object>))
  336.                supers))
  337.        (metaclass (or (get-keyword #:metaclass options #f)
  338.               (ensure-metaclass supers env))))
  339.  
  340.       ;; Verify that all direct slots are different and that we don't inherit
  341.       ;; several time from the same class
  342.       (let ((tmp1 (find-duplicate supers))
  343.         (tmp2 (find-duplicate (map slot-definition-name slots))))
  344.     (if tmp1
  345.         (goops-error "make-class: super class ~S is duplicate in class ~S"
  346.              tmp1 name))
  347.     (if tmp2
  348.         (goops-error "make-class: slot ~S is duplicate in class ~S"
  349.              tmp2 name)))
  350.  
  351.       ;; Everything seems correct, build the class
  352.       (apply make metaclass
  353.          #:dsupers supers
  354.          #:slots slots 
  355.          #:name name
  356.          #:environment env
  357.          options))))
  358.  
  359. ;;;
  360. ;;; {Generic functions and accessors}
  361. ;;;
  362.  
  363. (define define-generic
  364.   (procedure->macro
  365.     (lambda (exp env)
  366.       (let ((name (cadr exp)))
  367.     (cond ((not (symbol? name))
  368.            (goops-error "bad generic function name: ~S" name))
  369.           ((defined? name env)
  370.            `(define ,name
  371.           (if (is-a? ,name <generic>)
  372.               (make <generic> #:name ',name)
  373.               (ensure-generic ,name ',name))))
  374.           (else
  375.            `(define ,name (make <generic> #:name ',name))))))))
  376.  
  377. (define (make-generic . name)
  378.   (let ((name (and (pair? name) (car name))))
  379.     (make <generic> #:name name)))
  380.  
  381. (define (ensure-generic old-definition . name)
  382.   (let ((name (and (pair? name) (car name))))
  383.     (cond ((is-a? old-definition <generic>) old-definition)
  384.       ((procedure-with-setter? old-definition)
  385.        (make <generic-with-setter>
  386.          #:name name
  387.          #:default (procedure old-definition)
  388.          #:setter (setter old-definition)))
  389.       ((procedure? old-definition)
  390.        (make <generic> #:name name #:default old-definition))
  391.       (else (make <generic> #:name name)))))
  392.  
  393. (define define-accessor
  394.   (procedure->macro
  395.     (lambda (exp env)
  396.       (let ((name (cadr exp)))
  397.     (cond ((not (symbol? name))
  398.            (goops-error "bad accessor name: ~S" name))
  399.           ((defined? name env)
  400.            `(define ,name
  401.           (if (and (is-a? ,name <generic-with-setter>)
  402.                (is-a? (setter ,name) <generic>))
  403.               (make-accessor ',name)
  404.               (ensure-accessor ,name ',name))))
  405.           (else
  406.            `(define ,name (make-accessor ',name))))))))
  407.  
  408. (define (make-setter-name name)
  409.   (string->symbol (string-append "setter:" (symbol->string name))))
  410.  
  411. (define (make-accessor . name)
  412.   (let ((name (and (pair? name) (car name))))
  413.     (make <generic-with-setter>
  414.       #:name name
  415.       #:setter (make <generic>
  416.                  #:name (and name (make-setter-name name))))))
  417.  
  418. (define (ensure-accessor proc . name)
  419.   (let ((name (and (pair? name) (car name))))
  420.     (cond ((is-a? proc <generic-with-setter>)
  421.        (if (is-a? (setter proc) <generic>)
  422.            proc
  423.            (upgrade-generic-with-setter proc (setter proc))))
  424.       ((is-a? proc <generic>)
  425.        (upgrade-generic-with-setter proc (make-generic name)))
  426.       ((procedure-with-setter? proc)
  427.        (make <generic-with-setter>
  428.          #:name name
  429.          #:default (procedure proc)
  430.          #:setter (ensure-generic (setter proc) name)))
  431.       ((procedure? proc)
  432.        (ensure-accessor (ensure-generic proc name) name))
  433.       (else
  434.        (make-accessor name)))))
  435.  
  436. (define (upgrade-generic-with-setter generic setter)
  437.   (let ((methods (generic-function-methods generic))
  438.     (gws (make <generic-with-setter>
  439.            #:name (generic-function-name generic)
  440.            #:setter setter)))
  441.     ;; Steal old methods
  442.     (for-each (lambda (method)
  443.         (slot-set! method 'generic-function gws))
  444.           methods)
  445.     (slot-set! gws 'methods methods)
  446.     gws))
  447.  
  448. ;;;
  449. ;;; {Methods}
  450. ;;;
  451.  
  452. (define define-method
  453.   (procedure->memoizing-macro
  454.     (lambda (exp env)
  455.       (let ((head (cadr exp)))
  456.     (if (not (pair? head))
  457.         (goops-error "bad method head: ~S" head)
  458.         (let ((gf (car head)))
  459.           (cond ((and (pair? gf)
  460.               (eq? (car gf) 'setter)
  461.               (pair? (cdr gf))
  462.               (symbol? (cadr gf))
  463.               (null? (cddr gf)))
  464.              ;; named setter method
  465.              (let ((name (cadr gf)))
  466.                (cond ((not (symbol? name))
  467.                   `(add-method! (setter ,name)
  468.                         (method ,(cdadr exp)
  469.                             ,@(cddr exp))))
  470.                  ((defined? name env)
  471.                   `(begin
  472.                  ;; *fixme* Temporary hack for the current
  473.                  ;;         module system
  474.                  (if (not ,name)
  475.                      (define-accessor ,name))
  476.                  (add-method! (setter ,name)
  477.                           (method ,(cdadr exp)
  478.                               ,@(cddr exp)))))
  479.                  (else
  480.                   `(begin
  481.                  (define-accessor ,name)
  482.                  (add-method! (setter ,name)
  483.                           (method ,(cdadr exp)
  484.                               ,@(cddr exp))))))))
  485.             ((not (symbol? gf))
  486.              `(add-method! ,gf (method ,(cdadr exp) ,@(cddr exp))))
  487.             ((defined? gf env)
  488.              `(begin
  489.             ;; *fixme* Temporary hack for the current
  490.             ;;         module system
  491.             (if (not ,gf)
  492.                 (define-generic ,gf))
  493.             (add-method! ,gf
  494.                      (method ,(cdadr exp)
  495.                          ,@(cddr exp)))))
  496.             (else
  497.              `(begin
  498.             (define-generic ,gf)
  499.             (add-method! ,gf
  500.                      (method ,(cdadr exp)
  501.                          ,@(cddr exp))))))))))))
  502.  
  503. (define (make-method specializers procedure)
  504.   (make <method>
  505.     #:specializers specializers
  506.     #:procedure procedure))
  507.  
  508. (define method
  509.   (letrec ((specializers
  510.         (lambda (ls)
  511.           (cond ((null? ls) (list (list 'quote '())))
  512.             ((pair? ls) (cons (if (pair? (car ls))
  513.                       (cadar ls)
  514.                       '<top>)
  515.                       (specializers (cdr ls))))
  516.             (else '(<top>)))))
  517.        (formals
  518.         (lambda (ls)
  519.           (if (pair? ls)
  520.           (cons (if (pair? (car ls)) (caar ls) (car ls))
  521.             (formals (cdr ls)))
  522.           ls))))
  523.     (procedure->memoizing-macro
  524.       (lambda (exp env)
  525.     (let ((args (cadr exp))
  526.           (body (cddr exp)))
  527.       `(make <method>
  528.          #:specializers (cons* ,@(specializers args))
  529.          #:procedure (lambda ,(formals args)
  530.                    ,@(if (null? body)
  531.                      (list *unspecified*)
  532.                      body))))))))
  533.  
  534. ;;;
  535. ;;; {add-method!}
  536. ;;;
  537.  
  538. (define (add-method-in-classes! m)
  539.   ;; Add method in all the classes which appears in its specializers list
  540.   (for-each* (lambda (x)
  541.            (let ((dm (class-direct-methods x)))
  542.          (if (not (memv m dm))
  543.              (slot-set! x 'direct-methods (cons m dm)))))
  544.          (method-specializers m)))
  545.  
  546. (define (remove-method-in-classes! m)
  547.   ;; Remove method in all the classes which appears in its specializers list
  548.   (for-each* (lambda (x)
  549.            (slot-set! x
  550.               'direct-methods
  551.               (delv! m (class-direct-methods x))))
  552.          (method-specializers m)))
  553.  
  554. (define (compute-new-list-of-methods gf new)
  555.   (let ((new-spec (method-specializers new))
  556.     (methods  (generic-function-methods gf)))
  557.     (let loop ((l methods))
  558.       (if (null? l)
  559.       (cons new methods)
  560.       (if (equal? (method-specializers (car l)) new-spec)
  561.           (begin 
  562.         ;; This spec. list already exists. Remove old method from dependents
  563.         (remove-method-in-classes! (car l))
  564.         (set-car! l new) 
  565.         methods)
  566.           (loop (cdr l)))))))
  567.  
  568. (define (internal-add-method! gf m)
  569.   (slot-set! m  'generic-function gf)
  570.   (slot-set! gf 'methods (compute-new-list-of-methods gf m))
  571.   (let ((specializers (slot-ref m 'specializers)))
  572.     (slot-set! gf 'n-specialized
  573.            (max (length* specializers)
  574.             (slot-ref gf 'n-specialized))))
  575.   (%invalidate-method-cache! gf)
  576.   (add-method-in-classes! m)
  577.   *unspecified*)
  578.  
  579. (define-generic add-method!)
  580.  
  581. (internal-add-method! add-method!
  582.               (make <method>
  583.             #:specializers (list <generic> <method>)
  584.             #:procedure internal-add-method!))
  585.  
  586. (define-method (add-method! (proc <procedure>) (m <method>))
  587.   (if (generic-capability? proc)
  588.       (begin
  589.     (enable-primitive-generic! proc)
  590.     (add-method! proc m))
  591.       (next-method)))
  592.  
  593. (define-method (add-method! (pg <primitive-generic>) (m <method>))
  594.   (add-method! (primitive-generic-generic pg) m))
  595.  
  596. (define-method (add-method! obj (m <method>))
  597.   (goops-error "~S is not a valid generic function" obj))
  598.  
  599. ;;;
  600. ;;; {Access to meta objects}
  601. ;;;
  602.  
  603. ;;;
  604. ;;; Methods
  605. ;;;
  606. (define-method (method-source (m <method>))
  607.   (let* ((spec (map* class-name (slot-ref m 'specializers)))
  608.      (proc (procedure-source (slot-ref m 'procedure)))
  609.      (args (cadr proc))
  610.      (body (cddr proc)))
  611.     (cons 'method
  612.       (cons (map* list args spec)
  613.         body))))
  614.  
  615. ;;;
  616. ;;; Slots
  617. ;;;
  618. (define slot-definition-name car)
  619.  
  620. (define slot-definition-options cdr)
  621.  
  622. (define (slot-definition-allocation s)
  623.   (get-keyword #:allocation (cdr s) #:instance))
  624.  
  625. (define (slot-definition-getter s)
  626.   (get-keyword #:getter (cdr s) #f))
  627.  
  628. (define (slot-definition-setter s)
  629.   (get-keyword #:setter (cdr s) #f))
  630.  
  631. (define (slot-definition-accessor s)
  632.   (get-keyword #:accessor (cdr s) #f))
  633.  
  634. (define (slot-definition-init-value s)
  635.   ;; can be #f, so we can't use #f as non-value
  636.   (get-keyword #:init-value (cdr s) (make-unbound)))
  637.  
  638. (define (slot-definition-init-form s)
  639.   (get-keyword #:init-form (cdr s) (make-unbound)))
  640.  
  641. (define (slot-definition-init-thunk s)
  642.   (get-keyword #:init-thunk (cdr s) #f))
  643.  
  644. (define (slot-definition-init-keyword s)
  645.   (get-keyword #:init-keyword (cdr s) #f))
  646.  
  647. (define (class-slot-definition class slot-name)
  648.   (assq slot-name (class-slots class)))
  649.  
  650. (define (slot-init-function class slot-name)
  651.   (cadr (assq slot-name (slot-ref class 'getters-n-setters))))
  652.  
  653.  
  654. ;;;
  655. ;;; {Standard methods used by the C runtime}
  656. ;;;
  657.  
  658. ;;; Methods to compare objects
  659. ;;;
  660.  
  661. (define-method (eqv? x y)   #f)
  662. (define-method (equal? x y) (eqv? x y))
  663.  
  664. ;;; These following two methods are for backward compatibility only.
  665. ;;; They are not called by the Guile interpreter.
  666. ;;;
  667. (define-method (object-eqv? x y)    #f)
  668. (define-method (object-equal? x y)  (eqv? x y))
  669.  
  670. ;;;
  671. ;;; methods to display/write an object
  672. ;;;
  673.  
  674. ;     Code for writing objects must test that the slots they use are
  675. ;     bound. Otherwise a slot-unbound method will be called and will 
  676. ;     conduct to an infinite loop.
  677.  
  678. ;; Write
  679. (define (display-address o file)
  680.   (display (number->string (object-address o) 16) file))
  681.  
  682. (define-method (write o file)
  683.   (display "#<instance " file)
  684.   (display-address o file)
  685.   (display #\> file))
  686.  
  687. (define write-object (primitive-generic-generic write))
  688.  
  689. (define-method (write (o <object>) file)
  690.   (let ((class (class-of o)))
  691.     (if (slot-bound? class 'name)
  692.     (begin
  693.       (display "#<" file)
  694.       (display (class-name class) file)
  695.       (display #\space file)
  696.       (display-address o file)
  697.       (display #\> file))
  698.     (next-method))))
  699.  
  700. (define-method (write (o <foreign-object>) file)
  701.   (let ((class (class-of o)))
  702.     (if (slot-bound? class 'name)
  703.     (begin
  704.       (display "#<foreign-object " file)
  705.       (display (class-name class) file)
  706.       (display #\space file)
  707.       (display-address o file)
  708.       (display #\> file))
  709.     (next-method))))
  710.  
  711. (define-method (write (class <class>) file)
  712.   (let ((meta (class-of class)))
  713.     (if (and (slot-bound? class 'name)
  714.          (slot-bound? meta 'name))
  715.     (begin
  716.       (display "#<" file)
  717.       (display (class-name meta) file)
  718.       (display #\space file)
  719.       (display (class-name class) file)
  720.       (display #\space file)
  721.       (display-address class file)
  722.       (display #\> file))
  723.     (next-method))))
  724.  
  725. (define-method (write (gf <generic>) file)
  726.   (let ((meta (class-of gf)))
  727.     (if (and (slot-bound? meta 'name)
  728.          (slot-bound? gf 'methods))
  729.     (begin
  730.       (display "#<" file)
  731.       (display (class-name meta) file)
  732.       (let ((name (generic-function-name gf)))
  733.         (if name
  734.         (begin
  735.           (display #\space file)
  736.           (display name file))))
  737.       (display " (" file)
  738.       (display (length (generic-function-methods gf)) file)
  739.       (display ")>" file))
  740.     (next-method))))
  741.  
  742. (define-method (write (o <method>) file)
  743.   (let ((meta (class-of o)))
  744.     (if (and (slot-bound? meta 'name)
  745.          (slot-bound? o 'specializers))
  746.     (begin
  747.       (display "#<" file)
  748.       (display (class-name meta) file)
  749.       (display #\space file)
  750.       (display (map* (lambda (spec)
  751.                (if (slot-bound? spec 'name)
  752.                    (slot-ref spec 'name)
  753.                    spec))
  754.              (method-specializers o))
  755.            file)
  756.       (display #\space file)
  757.       (display-address o file)
  758.       (display #\> file))
  759.     (next-method))))
  760.  
  761. ;; Display (do the same thing as write by default)
  762. (define-method (display o file) 
  763.   (write-object o file))
  764.  
  765. ;;;
  766. ;;; slot access
  767. ;;;
  768.  
  769. (define (class-slot-g-n-s class slot-name)
  770.   (let* ((this-slot (assq slot-name (slot-ref class 'slots)))
  771.      (g-n-s (cddr (or (assq slot-name (slot-ref class 'getters-n-setters))
  772.               (slot-missing class slot-name)))))
  773.     (if (not (memq (slot-definition-allocation this-slot)
  774.            '(#:class #:each-subclass)))
  775.     (slot-missing class slot-name))
  776.     g-n-s))
  777.  
  778. (define (class-slot-ref class slot)
  779.   (let ((x ((car (class-slot-g-n-s class slot)) #f)))
  780.     (if (unbound? x)
  781.     (slot-unbound class slot)
  782.     x)))
  783.  
  784. (define (class-slot-set! class slot value)
  785.   ((cadr (class-slot-g-n-s class slot)) #f value))
  786.  
  787. (define-method (slot-unbound (c <class>) (o <object>) s)
  788.   (goops-error "Slot `~S' is unbound in object ~S" s o))
  789.  
  790. (define-method (slot-unbound (c <class>) s)
  791.   (goops-error "Slot `~S' is unbound in class ~S" s c))
  792.  
  793. (define-method (slot-unbound (o <object>))
  794.   (goops-error "Unbound slot in object ~S" o))
  795.  
  796. (define-method (slot-missing (c <class>) (o <object>) s)
  797.   (goops-error "No slot with name `~S' in object ~S" s o))
  798.   
  799. (define-method (slot-missing (c <class>) s)
  800.   (goops-error "No class slot with name `~S' in class ~S" s c))
  801.   
  802.  
  803. (define-method (slot-missing (c <class>) (o <object>) s value)
  804.   (slot-missing c o s))
  805.  
  806. ;;; Methods for the possible error we can encounter when calling a gf
  807.  
  808. (define-method (no-next-method (gf <generic>) args)
  809.   (goops-error "No next method when calling ~S\nwith arguments ~S" gf args))
  810.  
  811. (define-method (no-applicable-method (gf <generic>) args)
  812.   (goops-error "No applicable method for ~S in call ~S"
  813.            gf (cons (generic-function-name gf) args)))
  814.  
  815. (define-method (no-method (gf <generic>) args)
  816.   (goops-error "No method defined for ~S"  gf))
  817.  
  818. ;;;
  819. ;;; {Cloning functions (from rdeline@CS.CMU.EDU)}
  820. ;;;
  821.  
  822. (define-method (shallow-clone (self <object>))
  823.   (let ((clone (%allocate-instance (class-of self) '()))
  824.     (slots (map slot-definition-name
  825.             (class-slots (class-of self)))))
  826.     (for-each (lambda (slot)
  827.         (if (slot-bound? self slot)
  828.             (slot-set! clone slot (slot-ref self slot))))
  829.           slots)
  830.     clone))
  831.  
  832. (define-method (deep-clone  (self <object>))
  833.   (let ((clone (%allocate-instance (class-of self) '()))
  834.     (slots (map slot-definition-name
  835.             (class-slots (class-of self)))))
  836.     (for-each (lambda (slot)
  837.         (if (slot-bound? self slot)
  838.             (slot-set! clone slot
  839.                    (let ((value (slot-ref self slot)))
  840.                  (if (instance? value)
  841.                      (deep-clone value)
  842.                      value)))))
  843.           slots)
  844.     clone))
  845.  
  846. ;;;
  847. ;;; {Class redefinition utilities}
  848. ;;;
  849.  
  850. ;;; (class-redefinition OLD NEW)
  851. ;;;
  852.  
  853. ;;; Has correct the following conditions:
  854.  
  855. ;;; Methods
  856. ;;; 
  857. ;;; 1. New accessor specializers refer to new header
  858. ;;; 
  859. ;;; Classes
  860. ;;; 
  861. ;;; 1. New class cpl refers to the new class header
  862. ;;; 2. Old class header exists on old super classes direct-subclass lists
  863. ;;; 3. New class header exists on new super classes direct-subclass lists
  864.  
  865. (define-method (class-redefinition (old <class>) (new <class>))
  866.   ;; Work on direct methods:
  867.   ;;        1. Remove accessor methods from the old class 
  868.   ;;        2. Patch the occurences of new in the specializers by old
  869.   ;;        3. Displace the methods from old to new
  870.   (remove-class-accessors! old)                    ;; -1-
  871.   (let ((methods (class-direct-methods new)))
  872.     (for-each (lambda (m)
  873.                   (update-direct-method! m new old))    ;; -2-
  874.               methods)
  875.     (slot-set! new
  876.            'direct-methods
  877.            (append methods (class-direct-methods old))))
  878.  
  879.   ;; Substitute old for new in new cpl
  880.   (set-car! (slot-ref new 'cpl) old)
  881.   
  882.   ;; Remove the old class from the direct-subclasses list of its super classes
  883.   (for-each (lambda (c) (slot-set! c 'direct-subclasses
  884.                    (delv! old (class-direct-subclasses c))))
  885.         (class-direct-supers old))
  886.  
  887.   ;; Replace the new class with the old in the direct-subclasses of the supers
  888.   (for-each (lambda (c)
  889.           (slot-set! c 'direct-subclasses
  890.              (cons old (delv! new (class-direct-subclasses c)))))
  891.         (class-direct-supers new))
  892.  
  893.   ;; Swap object headers
  894.   (%modify-class old new)
  895.  
  896.   ;; Now old is NEW!
  897.  
  898.   ;; Redefine all the subclasses of old to take into account modification
  899.   (for-each 
  900.        (lambda (c)
  901.      (update-direct-subclass! c new old))
  902.        (class-direct-subclasses new))
  903.  
  904.   ;; Invalidate class so that subsequent instances slot accesses invoke
  905.   ;; change-object-class
  906.   (slot-set! new 'redefined old)
  907.   (%invalidate-class new) ;must come after slot-set!
  908.  
  909.   old)
  910.  
  911. ;;;
  912. ;;; remove-class-accessors!
  913. ;;;
  914.  
  915. (define-method (remove-class-accessors! (c <class>))
  916.   (for-each (lambda (m)
  917.           (if (is-a? m <accessor-method>)
  918.           (let ((gf (slot-ref m 'generic-function)))
  919.             ;; remove the method from its GF
  920.             (slot-set! gf 'methods
  921.                    (delq1! m (slot-ref gf 'methods)))
  922.             (%invalidate-method-cache! gf)
  923.             ;; remove the method from its specializers
  924.             (remove-method-in-classes! m))))
  925.         (class-direct-methods c)))
  926.  
  927. ;;;
  928. ;;; update-direct-method!
  929. ;;;
  930.  
  931. (define-method (update-direct-method! (m  <method>)
  932.                       (old <class>)
  933.                       (new <class>))
  934.   (let loop ((l (method-specializers m)))
  935.     ;; Note: the <top> in dotted list is never used. 
  936.     ;; So we can work as if we had only proper lists.
  937.     (if (pair? l)             
  938.     (begin
  939.       (if (eq? (car l) old)  
  940.           (set-car! l new))
  941.       (loop (cdr l))))))
  942.  
  943. ;;;
  944. ;;; update-direct-subclass!
  945. ;;;
  946.  
  947. (define-method (update-direct-subclass! (c <class>)
  948.                     (old <class>)
  949.                     (new <class>))
  950.   (class-redefinition c
  951.               (make-class (class-direct-supers c)
  952.                   (class-direct-slots c)
  953.                   #:name (class-name c)
  954.                   #:environment (slot-ref c 'environment)
  955.                   #:metaclass (class-of c))))
  956.  
  957. ;;;
  958. ;;; {Utilities for INITIALIZE methods}
  959. ;;;
  960.  
  961. ;;; compute-slot-accessors
  962. ;;;
  963. (define (compute-slot-accessors class slots env)
  964.   (for-each
  965.       (lambda (s g-n-s)
  966.     (let ((name            (slot-definition-name     s))
  967.           (getter-function (slot-definition-getter   s))
  968.           (setter-function (slot-definition-setter   s))
  969.           (accessor        (slot-definition-accessor s)))
  970.       (if getter-function
  971.           (add-method! getter-function
  972.                (compute-getter-method class g-n-s)))
  973.       (if setter-function
  974.           (add-method! setter-function
  975.                (compute-setter-method class g-n-s)))
  976.       (if accessor
  977.           (begin
  978.         (add-method! accessor
  979.                  (compute-getter-method class g-n-s))
  980.         (add-method! (setter accessor)
  981.                  (compute-setter-method class g-n-s))))))
  982.       slots (slot-ref class 'getters-n-setters)))
  983.  
  984. (define-method (compute-getter-method (class <class>) slotdef)
  985.   (let ((init-thunk (cadr slotdef))
  986.     (g-n-s (cddr slotdef)))
  987.     (make <accessor-method>
  988.           #:specializers (list class)
  989.       #:procedure (cond ((pair? g-n-s)
  990.                  (make-generic-bound-check-getter (car g-n-s)))
  991.                 (init-thunk
  992.                  (standard-get g-n-s))
  993.                 (else
  994.                  (bound-check-get g-n-s)))
  995.       #:slot-definition slotdef)))
  996.  
  997. (define-method (compute-setter-method (class <class>) slotdef)
  998.   (let ((g-n-s (cddr slotdef)))
  999.     (make <accessor-method>
  1000.           #:specializers (list class <top>)
  1001.       #:procedure (if (pair? g-n-s)
  1002.               (cadr g-n-s)
  1003.               (standard-set g-n-s))
  1004.       #:slot-definition slotdef)))
  1005.  
  1006. (define (make-generic-bound-check-getter proc)
  1007.   (let ((source (and (closure? proc) (procedure-source proc))))
  1008.     (if (and source (null? (cdddr source)))
  1009.     (let ((obj (caadr source)))
  1010.       ;; smart closure compilation
  1011.       (local-eval
  1012.        `(lambda (,obj) (,assert-bound ,(caddr source) ,obj))
  1013.        (procedure-environment proc)))
  1014.     (lambda (o) (assert-bound (proc o) o)))))
  1015.  
  1016. (define n-standard-accessor-methods 10)
  1017.  
  1018. (define bound-check-get-methods (make-vector n-standard-accessor-methods #f))
  1019. (define standard-get-methods (make-vector n-standard-accessor-methods #f))
  1020. (define standard-set-methods (make-vector n-standard-accessor-methods #f))
  1021.  
  1022. (define (standard-accessor-method make methods)
  1023.   (lambda (index)
  1024.     (cond ((>= index n-standard-accessor-methods) (make index))
  1025.       ((vector-ref methods index))
  1026.       (else (let ((m (make index)))
  1027.           (vector-set! methods index m)
  1028.           m)))))
  1029.  
  1030. (define (make-bound-check-get index)
  1031.   (local-eval `(lambda (o) (@assert-bound-ref o ,index)) (the-environment)))
  1032.  
  1033. (define (make-get index)
  1034.   (local-eval `(lambda (o) (@slot-ref o ,index)) (the-environment)))
  1035.  
  1036. (define (make-set index)
  1037.   (local-eval `(lambda (o v) (@slot-set! o ,index v)) (the-environment)))
  1038.  
  1039. (define bound-check-get
  1040.   (standard-accessor-method make-bound-check-get bound-check-get-methods))
  1041. (define standard-get (standard-accessor-method make-get standard-get-methods))
  1042. (define standard-set (standard-accessor-method make-set standard-set-methods))
  1043.  
  1044. ;;; compute-getters-n-setters
  1045. ;;;
  1046. (define (make-thunk thunk)
  1047.   (lambda () (thunk)))
  1048.  
  1049. (define (compute-getters-n-setters class slots env)
  1050.  
  1051.   (define (compute-slot-init-function name s)
  1052.     (or (let ((thunk (slot-definition-init-thunk s)))
  1053.       (and thunk
  1054.            (cond ((not (thunk? thunk))
  1055.               (goops-error "Bad init-thunk for slot `~S' in ~S: ~S"
  1056.                    name class thunk))
  1057.              ((closure? thunk) thunk)
  1058.              (else (make-thunk thunk)))))
  1059.     (let ((init (slot-definition-init-value s)))
  1060.       (and (not (unbound? init))
  1061.            (lambda () init)))))
  1062.  
  1063.   (define (verify-accessors slot l)
  1064.     (cond ((integer? l))
  1065.       ((not (and (list? l) (= (length l) 2)))
  1066.        (goops-error "Bad getter and setter for slot `~S' in ~S: ~S"
  1067.             slot class l))
  1068.       (else
  1069.        (let ((get (car l)) 
  1070.          (set (cadr l)))
  1071.          (if (not (and (closure? get)
  1072.                (= (car (procedure-property get 'arity)) 1)))
  1073.          (goops-error "Bad getter closure for slot `~S' in ~S: ~S"
  1074.                   slot class get))
  1075.          (if (not (and (closure? set)
  1076.                (= (car (procedure-property set 'arity)) 2)))
  1077.          (goops-error "Bad setter closure for slot `~S' in ~S: ~S"
  1078.                   slot class set))))))
  1079.  
  1080.   (map (lambda (s)
  1081.      ;; The strange treatment of nfields is due to backward compatibility.
  1082.      (let* ((index (slot-ref class 'nfields))
  1083.         (g-n-s (compute-get-n-set class s))
  1084.         (size (- (slot-ref class 'nfields) index))
  1085.         (name  (slot-definition-name s)))
  1086.        ;; NOTE: The following is interdependent with C macros
  1087.        ;; defined above goops.c:scm_sys_prep_layout_x.
  1088.        ;;
  1089.        ;; For simple instance slots, we have the simplest form
  1090.        ;; '(name init-function . index)
  1091.        ;; For other slots we have
  1092.        ;; '(name init-function getter setter . alloc)
  1093.        ;; where alloc is:
  1094.        ;;   '(index size) for instance allocated slots
  1095.        ;;   '() for other slots
  1096.        (verify-accessors name g-n-s)
  1097.        (cons name
  1098.          (cons (compute-slot-init-function name s)
  1099.                (if (or (integer? g-n-s)
  1100.                    (zero? size))
  1101.                g-n-s
  1102.                (append g-n-s (list index size)))))))
  1103.        slots))
  1104.  
  1105. ;;; compute-cpl
  1106. ;;;
  1107. ;;; Correct behaviour:
  1108. ;;;
  1109. ;;; (define-class food ())
  1110. ;;; (define-class fruit (food))
  1111. ;;; (define-class spice (food))
  1112. ;;; (define-class apple (fruit))
  1113. ;;; (define-class cinnamon (spice))
  1114. ;;; (define-class pie (apple cinnamon))
  1115. ;;; => cpl (pie) = pie apple fruit cinnamon spice food object top
  1116. ;;;
  1117. ;;; (define-class d ())
  1118. ;;; (define-class e ())
  1119. ;;; (define-class f ())
  1120. ;;; (define-class b (d e))
  1121. ;;; (define-class c (e f))
  1122. ;;; (define-class a (b c))
  1123. ;;; => cpl (a) = a b d c e f object top
  1124. ;;;
  1125.  
  1126. (define-method (compute-cpl (class <class>))
  1127.   (compute-std-cpl class class-direct-supers))
  1128.  
  1129. ;; Support
  1130.  
  1131. (define (only-non-null lst)
  1132.   (filter (lambda (l) (not (null? l))) lst))
  1133.  
  1134. (define (compute-std-cpl c get-direct-supers)
  1135.   (let ((c-direct-supers (get-direct-supers c)))
  1136.     (merge-lists (list c)
  1137.                  (only-non-null (append (map class-precedence-list
  1138.                          c-direct-supers)
  1139.                                         (list c-direct-supers))))))
  1140.  
  1141. (define (merge-lists reversed-partial-result inputs)
  1142.   (cond
  1143.    ((every null? inputs)
  1144.     (reverse! reversed-partial-result))
  1145.    (else
  1146.     (let* ((candidate (lambda (c)
  1147.                         (and (not (any (lambda (l)
  1148.                                          (memq c (cdr l)))
  1149.                                        inputs))
  1150.                              c)))
  1151.            (candidate-car (lambda (l)
  1152.                             (and (not (null? l))
  1153.                                  (candidate (car l)))))
  1154.            (next (any candidate-car inputs)))
  1155.       (if (not next)
  1156.           (goops-error "merge-lists: Inconsistent precedence graph"))
  1157.       (let ((remove-next (lambda (l)
  1158.                            (if (eq? (car l) next)
  1159.                                (cdr l)
  1160.                              l))))
  1161.         (merge-lists (cons next reversed-partial-result)
  1162.                      (only-non-null (map remove-next inputs))))))))
  1163.  
  1164. ;; Modified from TinyClos:
  1165. ;;
  1166. ;; A simple topological sort.
  1167. ;;
  1168. ;; It's in this file so that both TinyClos and Objects can use it.
  1169. ;;
  1170. ;; This is a fairly modified version of code I originally got from Anurag
  1171. ;; Mendhekar <anurag@moose.cs.indiana.edu>.
  1172. ;;
  1173.  
  1174. (define (compute-clos-cpl c get-direct-supers)
  1175.   (top-sort ((build-transitive-closure get-direct-supers) c)
  1176.         ((build-constraints get-direct-supers) c)
  1177.         (std-tie-breaker get-direct-supers)))
  1178.  
  1179.  
  1180. (define (top-sort elements constraints tie-breaker)
  1181.   (let loop ((elements    elements)
  1182.          (constraints constraints)
  1183.          (result      '()))
  1184.     (if (null? elements)
  1185.     result
  1186.     (let ((can-go-in-now
  1187.            (filter
  1188.         (lambda (x)
  1189.           (every (lambda (constraint)
  1190.                (or (not (eq? (cadr constraint) x))
  1191.                    (memq (car constraint) result)))
  1192.              constraints))
  1193.         elements)))
  1194.       (if (null? can-go-in-now)
  1195.           (goops-error "top-sort: Invalid constraints")
  1196.           (let ((choice (if (null? (cdr can-go-in-now))
  1197.                 (car can-go-in-now)
  1198.                 (tie-breaker result
  1199.                          can-go-in-now))))
  1200.         (loop
  1201.          (filter (lambda (x) (not (eq? x choice)))
  1202.                  elements)
  1203.          constraints
  1204.          (append result (list choice)))))))))
  1205.  
  1206. (define (std-tie-breaker get-supers)
  1207.   (lambda (partial-cpl min-elts)
  1208.     (let loop ((pcpl (reverse partial-cpl)))
  1209.       (let ((current-elt (car pcpl)))
  1210.     (let ((ds-of-ce (get-supers current-elt)))
  1211.       (let ((common (filter (lambda (x)
  1212.                       (memq x ds-of-ce))
  1213.                     min-elts)))
  1214.         (if (null? common)
  1215.         (if (null? (cdr pcpl))
  1216.             (goops-error "std-tie-breaker: Nothing valid")
  1217.             (loop (cdr pcpl)))
  1218.         (car common))))))))
  1219.  
  1220.  
  1221. (define (build-transitive-closure get-follow-ons)
  1222.   (lambda (x)
  1223.     (let track ((result '())
  1224.         (pending (list x)))
  1225.       (if (null? pending)
  1226.       result
  1227.       (let ((next (car pending)))
  1228.         (if (memq next result)
  1229.         (track result (cdr pending))
  1230.         (track (cons next result)
  1231.                (append (get-follow-ons next)
  1232.                    (cdr pending)))))))))
  1233.  
  1234. (define (build-constraints get-follow-ons)
  1235.   (lambda (x)
  1236.     (let loop ((elements ((build-transitive-closure get-follow-ons) x))
  1237.            (this-one '())
  1238.            (result '()))
  1239.       (if (or (null? this-one) (null? (cdr this-one)))
  1240.       (if (null? elements)
  1241.           result
  1242.           (loop (cdr elements)
  1243.             (cons (car elements)
  1244.               (get-follow-ons (car elements)))
  1245.             result))
  1246.       (loop elements
  1247.         (cdr this-one)
  1248.         (cons (list (car this-one) (cadr this-one))
  1249.               result))))))
  1250.  
  1251. ;;; compute-get-n-set
  1252. ;;;
  1253. (define-method (compute-get-n-set (class <class>) s)
  1254.   (case (slot-definition-allocation s)
  1255.     ((#:instance) ;; Instance slot
  1256.      ;; get-n-set is just its offset
  1257.      (let ((already-allocated (slot-ref class 'nfields)))
  1258.        (slot-set! class 'nfields (+ already-allocated 1))
  1259.        already-allocated))
  1260.  
  1261.     ((#:class)  ;; Class slot
  1262.      ;; Class-slots accessors are implemented as 2 closures around 
  1263.      ;; a Scheme variable. As instance slots, class slots must be
  1264.      ;; unbound at init time.
  1265.      (let ((name (slot-definition-name s)))
  1266.        (if (memq name (map slot-definition-name (class-direct-slots class)))
  1267.        ;; This slot is direct; create a new shared variable
  1268.        (make-closure-variable class)
  1269.        ;; Slot is inherited. Find its definition in superclass
  1270.        (let loop ((l (cdr (class-precedence-list class))))
  1271.          (let ((r (assoc name (slot-ref (car l) 'getters-n-setters))))
  1272.            (if r
  1273.            (cddr r)
  1274.            (loop (cdr l))))))))
  1275.  
  1276.     ((#:each-subclass) ;; slot shared by instances of direct subclass.
  1277.      ;; (Thomas Buerger, April 1998)
  1278.      (make-closure-variable class))
  1279.  
  1280.     ((#:virtual) ;; No allocation
  1281.      ;; slot-ref and slot-set! function must be given by the user
  1282.      (let ((get (get-keyword #:slot-ref  (slot-definition-options s) #f))
  1283.        (set (get-keyword #:slot-set! (slot-definition-options s) #f))
  1284.        (env (class-environment class)))
  1285.        (if (not (and get set))
  1286.        (goops-error "You must supply a :slot-ref and a :slot-set! in ~S"
  1287.             s))
  1288.        (list get set)))
  1289.     (else    (next-method))))
  1290.  
  1291. (define (make-closure-variable class)
  1292.   (let ((shared-variable (make-unbound)))
  1293.     (list (lambda (o) shared-variable)
  1294.       (lambda (o v) (set! shared-variable v)))))
  1295.  
  1296. (define-method (compute-get-n-set (o <object>) s)
  1297.   (goops-error "Allocation \"~S\" is unknown" (slot-definition-allocation s)))
  1298.  
  1299. (define-method (compute-slots (class <class>))
  1300.   (%compute-slots class))
  1301.  
  1302. ;;;
  1303. ;;; {Initialize}
  1304. ;;;
  1305.  
  1306. (define-method (initialize (object <object>) initargs)
  1307.   (%initialize-object object initargs))
  1308.  
  1309. (define-method (initialize (class <class>) initargs)
  1310.   (next-method)
  1311.   (let ((dslots (get-keyword #:slots initargs '()))
  1312.     (supers (get-keyword #:dsupers      initargs '()))
  1313.     (env    (get-keyword #:environment initargs (top-level-env))))
  1314.  
  1315.     (slot-set! class 'name          (get-keyword #:name initargs '???))
  1316.     (slot-set! class 'direct-supers     supers)
  1317.     (slot-set! class 'direct-slots      dslots)
  1318.     (slot-set! class 'direct-subclasses '())
  1319.     (slot-set! class 'direct-methods    '())
  1320.     (slot-set! class 'cpl        (compute-cpl class))
  1321.     (slot-set! class 'redefined        #f)
  1322.     (slot-set! class 'environment    env)
  1323.     (let ((slots (compute-slots class)))
  1324.       (slot-set! class 'slots            slots)
  1325.       (slot-set! class 'nfields            0)
  1326.       (slot-set! class 'getters-n-setters (compute-getters-n-setters class 
  1327.                                      slots 
  1328.                                      env))
  1329.       ;; Build getters - setters - accessors
  1330.       (compute-slot-accessors class slots env))
  1331.  
  1332.     ;; Update the "direct-subclasses" of each inherited classes
  1333.     (for-each (lambda (x)
  1334.         (slot-set! x
  1335.                'direct-subclasses 
  1336.                (cons class (slot-ref x 'direct-subclasses))))
  1337.           supers)
  1338.  
  1339.     ;; Support for the underlying structs:
  1340.     
  1341.     ;; Inherit class flags (invisible on scheme level) from supers
  1342.     (%inherit-magic! class supers)
  1343.  
  1344.     ;; Set the layout slot
  1345.     (%prep-layout! class)))
  1346.  
  1347. (define (initialize-object-procedure object initargs)
  1348.   (let ((proc (get-keyword #:procedure initargs #f)))
  1349.     (cond ((not proc))
  1350.       ((pair? proc)
  1351.        (apply set-object-procedure! object proc))
  1352.       ((valid-object-procedure? proc)
  1353.        (set-object-procedure! object proc))
  1354.       (else
  1355.        (set-object-procedure! object
  1356.                   (lambda args (apply proc args)))))))
  1357.  
  1358. (define-method (initialize (class <operator-class>) initargs)
  1359.   (next-method)
  1360.   (initialize-object-procedure class initargs))
  1361.  
  1362. (define-method (initialize (owsc <operator-with-setter-class>) initargs)
  1363.   (next-method)
  1364.   (%set-object-setter! owsc (get-keyword #:setter initargs #f)))
  1365.  
  1366. (define-method (initialize (entity <entity>) initargs)
  1367.   (next-method)
  1368.   (initialize-object-procedure entity initargs))
  1369.  
  1370. (define-method (initialize (ews <entity-with-setter>) initargs)
  1371.   (next-method)
  1372.   (%set-object-setter! ews (get-keyword #:setter initargs #f)))
  1373.  
  1374. (define-method (initialize (generic <generic>) initargs)
  1375.   (let ((previous-definition (get-keyword #:default initargs #f))
  1376.     (name (get-keyword #:name initargs #f)))
  1377.     (next-method)
  1378.     (slot-set! generic 'methods (if (is-a? previous-definition <procedure>)
  1379.                     (list (make <method>
  1380.                         #:specializers <top>
  1381.                         #:procedure
  1382.                         (lambda l
  1383.                           (apply previous-definition 
  1384.                              l))))
  1385.                     '()))
  1386.     (if name
  1387.     (set-procedure-property! generic 'name name))
  1388.     ))
  1389.  
  1390. (define dummy-procedure (lambda args *unspecified*))
  1391.  
  1392. (define-method (initialize (method <method>) initargs)
  1393.   (next-method)
  1394.   (slot-set! method 'generic-function (get-keyword #:generic-function initargs #f))
  1395.   (slot-set! method 'specializers (get-keyword #:specializers initargs '()))
  1396.   (slot-set! method 'procedure
  1397.          (get-keyword #:procedure initargs dummy-procedure))
  1398.   (slot-set! method 'code-table '()))
  1399.  
  1400. (define-method (initialize (obj <foreign-object>) initargs))
  1401.  
  1402. ;;;
  1403. ;;; {Change-class}
  1404. ;;;
  1405.  
  1406. (define (change-object-class old-instance old-class new-class)
  1407.   (let ((new-instance (allocate-instance new-class '())))
  1408.     ;; Initalize the slot of the new instance
  1409.     (for-each (lambda (slot)
  1410.         (if (and (slot-exists-using-class? old-class old-instance slot)
  1411.              (eq? (slot-definition-allocation
  1412.                    (class-slot-definition old-class slot))
  1413.                   #:instance)
  1414.              (slot-bound-using-class? old-class old-instance slot))
  1415.             ;; Slot was present and allocated in old instance; copy it 
  1416.             (slot-set-using-class!
  1417.              new-class 
  1418.              new-instance 
  1419.              slot 
  1420.              (slot-ref-using-class old-class old-instance slot))
  1421.             ;; slot was absent; initialize it with its default value
  1422.             (let ((init (slot-init-function new-class slot)))
  1423.               (if init
  1424.               (slot-set-using-class!
  1425.                    new-class 
  1426.                    new-instance 
  1427.                    slot
  1428.                    (apply init '()))))))
  1429.           (map slot-definition-name (class-slots new-class)))
  1430.     ;; Exchange old and new instance in place to keep pointers valid
  1431.     (%modify-instance old-instance new-instance)
  1432.     ;; Allow class specific updates of instances (which now are swapped)
  1433.     (update-instance-for-different-class new-instance old-instance)
  1434.     old-instance))
  1435.  
  1436.  
  1437. (define-method (update-instance-for-different-class (old-instance <object>)
  1438.                             (new-instance
  1439.                              <object>))
  1440.   ;;not really important what we do, we just need a default method
  1441.   new-instance)
  1442.  
  1443. (define-method (change-class (old-instance <object>) (new-class <class>))
  1444.   (change-object-class old-instance (class-of old-instance) new-class))
  1445.  
  1446. ;;;
  1447. ;;; {make}
  1448. ;;;
  1449. ;;; A new definition which overwrites the previous one which was built-in
  1450. ;;;
  1451.  
  1452. (define-method (allocate-instance (class <class>) initargs)
  1453.   (%allocate-instance class initargs))
  1454.  
  1455. (define-method (make-instance (class <class>) . initargs)
  1456.   (let ((instance (allocate-instance class initargs)))
  1457.     (initialize instance initargs)
  1458.     instance))
  1459.  
  1460. (define make make-instance)
  1461.  
  1462. ;;;
  1463. ;;; {apply-generic}
  1464. ;;;
  1465. ;;; Protocol for calling standard generic functions.  This protocol is
  1466. ;;; not used for real <generic> functions (in this case we use a
  1467. ;;; completely C hard-coded protocol).  Apply-generic is used by
  1468. ;;; goops for calls to subclasses of <generic> and <generic-with-setter>.
  1469. ;;; The code below is similar to the first MOP described in AMOP. In
  1470. ;;; particular, it doesn't used the currified approach to gf
  1471. ;;; call. There are 2 reasons for that:
  1472. ;;;   - the protocol below is exposed to mimic completely the one written in C
  1473. ;;;   - the currified protocol would be imho inefficient in C.
  1474. ;;;
  1475.  
  1476. (define-method (apply-generic (gf <generic>) args)
  1477.   (if (null? (slot-ref gf 'methods))
  1478.       (no-method gf args))
  1479.   (let ((methods (compute-applicable-methods gf args)))
  1480.     (if methods
  1481.     (apply-methods gf (sort-applicable-methods gf methods args) args)
  1482.     (no-applicable-method gf args))))
  1483.  
  1484. ;; compute-applicable-methods is bound to %compute-applicable-methods.
  1485. ;; *fixme* use let
  1486. (define %%compute-applicable-methods
  1487.   (make <generic> #:name 'compute-applicable-methods))
  1488.  
  1489. (define-method (%%compute-applicable-methods (gf <generic>) args)
  1490.   (%compute-applicable-methods gf args))
  1491.  
  1492. (set! compute-applicable-methods %%compute-applicable-methods)
  1493.  
  1494. (define-method (sort-applicable-methods (gf <generic>) methods args)
  1495.   (let ((targs (map class-of args)))
  1496.     (sort methods (lambda (m1 m2) (method-more-specific? m1 m2 targs)))))
  1497.  
  1498. (define-method (method-more-specific? (m1 <method>) (m2 <method>) targs)
  1499.   (%method-more-specific? m1 m2 targs))
  1500.  
  1501. (define-method (apply-method (gf <generic>) methods build-next args)
  1502.   (apply (method-procedure (car methods))
  1503.      (build-next (cdr methods) args)
  1504.      args))
  1505.  
  1506. (define-method (apply-methods (gf <generic>) (l <list>) args)
  1507.   (letrec ((next (lambda (procs args)
  1508.            (lambda new-args
  1509.              (let ((a (if (null? new-args) args new-args)))
  1510.                (if (null? procs)
  1511.                (no-next-method gf a)
  1512.                (apply-method gf procs next a)))))))
  1513.     (apply-method gf l next args)))
  1514.  
  1515. ;; We don't want the following procedure to turn up in backtraces:
  1516. (for-each (lambda (proc)
  1517.         (set-procedure-property! proc 'system-procedure #t))
  1518.       (list slot-unbound
  1519.         slot-missing
  1520.         no-next-method
  1521.         no-applicable-method
  1522.         no-method
  1523.         ))
  1524.  
  1525. ;;;
  1526. ;;; {<composite-metaclass> and <active-metaclass>}
  1527. ;;;
  1528.  
  1529. ;(autoload "active-slot"    <active-metaclass>)
  1530. ;(autoload "composite-slot" <composite-metaclass>)
  1531. ;(export <composite-metaclass> <active-metaclass>)
  1532.  
  1533. ;;;
  1534. ;;; {Tools}
  1535. ;;;
  1536.  
  1537. ;; list2set
  1538. ;;
  1539. ;; duplicate the standard list->set function but using eq instead of
  1540. ;; eqv which really sucks a lot, uselessly here
  1541. ;;
  1542. (define (list2set l)           
  1543.   (let loop ((l l)
  1544.          (res '()))
  1545.     (cond               
  1546.      ((null? l) res)
  1547.      ((memq (car l) res) (loop (cdr l) res))
  1548.      (else (loop (cdr l) (cons (car l) res))))))
  1549.  
  1550. (define (class-subclasses c)
  1551.   (letrec ((allsubs (lambda (c)
  1552.               (cons c (mapappend allsubs
  1553.                      (class-direct-subclasses c))))))
  1554.     (list2set (cdr (allsubs c)))))
  1555.  
  1556. (define (class-methods c)
  1557.   (list2set (mapappend class-direct-methods
  1558.                (cons c (class-subclasses c)))))
  1559.  
  1560. ;;;
  1561. ;;; {Final initialization}
  1562. ;;;
  1563.  
  1564. ;; Tell C code that the main bulk of Goops has been loaded
  1565. (%goops-loaded)
  1566.