ecl/src/clos/kernel.lsp

161 lines
5.3 KiB
Common Lisp

;;;; Copyright (c) 1992, Giuseppe Attardi.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Library General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 2 of the License, or (at your option) any later version.
;;;;
;;;; See file '../Copyright' for full details.
(in-package "CLOS")
(defconstant *default-method-cache-size* 64 "Size of hash tables for methods")
;;; ----------------------------------------------------------------------
(defun class-of (object)
(if (si:instancep object)
(si:instance-class object)
(closest-class (type-of object))))
(defun closest-class (type)
(or (find-class type nil)
(case type
((FIXNUM BIGNUM) (find-class 'integer))
((SHORT-FLOAT LONG-FLOAT) (find-class 'float))
((BASE-CHAR STANDARD-CHAR EXTENDED-CHAR) (find-class 'character))
(SIMPLE-ARRAY (find-class 'array))
(SIMPLE-VECTOR (find-class 'vector))
(SIMPLE-BIT-VECTOR (find-class 'bit-vector))
(SIMPLE-STRING (find-class 'string))
((CONT THREAD DISPATCH-FUNCTION) (find-class 't)))))
;;; ----------------------------------------------------------------------
;;; Each instance has a pointer to the class of which it is an instance.
;;; Its is used to search for methods and class variables.
;;; Bootstrapping for class Class.
(defun search-make-instance (obj)
(declare (si::c-local))
(let* ((gfun (symbol-function (if (si::tracing-body 'make-instance)
(get-sysprop 'make-instance 'si::traced)
'make-instance)))
(table (si:gfun-method-ht gfun))
(key (list (class-name (si:instance-class obj))))
(method (si:method-ht-get key table)))
(unless method
(setq method (compute-applicable-methods
(si:gfun-instance gfun)
(list obj))))
method))
(defun classp (obj)
(and (si:instancep obj)
(search-make-instance obj)
t))
(defun metaclassp (obj)
(declare (si::c-local))
(and (si:instancep obj)
(search-make-instance (si:instance-class obj))
(search-make-instance obj)
t))
;;; ----------------------------------------------------------------------
;;; Object initializations
(defun allocate-instance (class)
(si:allocate-raw-instance class (length (class-slots class))))
;;; ----------------------------------------------------------------------
;;; Methods
(defun install-method (name qualifiers specializers lambda-list doc plist
fun &rest options)
(declare (ignore doc)
(notinline cos ensure-generic-function method-class))
; (record-definition 'method `(method ,name ,@qualifiers ,specializers))
(let* ((gf (ensure-generic-function name :lambda-list lambda-list))
(method (make-method qualifiers specializers lambda-list
fun plist options gf (method-class gf)))
(dispatcher (generic-function-dispatcher gf)))
;; update the spec-how of the gfun
;; computing the or of the previous value and the new one
(do ((i 0 (1+ i))
(l specializers (cdr l))
(spec-how)
(spec-how-old))
((null l))
(declare (fixnum i))
(setq spec-how (first l)
spec-how-old (si:gfun-spec-how-ref dispatcher i))
(if (consp spec-how) ; an eql list
(if (consp spec-how-old)
(push (second spec-how) (si:gfun-spec-how-ref dispatcher i))
(setf (si:gfun-spec-how-ref dispatcher i) (cdr spec-how)))
(unless (consp spec-how-old) ; either T or NIL
(setf (si:gfun-spec-how-ref dispatcher i)
(or spec-how spec-how-old)))))
(add-method gf method)))
;;; ----------------------------------------------------------------------
;;; early versions
(defun method-class (gfun) 'standard-method)
(defun methods (gf) (si:instance-ref gf 7))
;(defun generic-function-dispatcher (gf) (si:instance-ref gf 6)) anticipata
(defun make-gfun (name lambda-list)
(let* ((nargs
(or (position-if
#'(lambda (x)
(member x '(&OPTIONAL &REST &KEY &ALLOW-OTHER-KEYS &AUX)
:test #'eq))
lambda-list)
(length lambda-list)))
(gfun
(si:allocate-gfun
name
nargs
(make-hash-table
:test #'equal
;; use fixnums as limits for efficiency:
:size *default-method-cache-size*
:rehash-size #.(/ *default-method-cache-size* 2)
:rehash-threshold #.(/ *default-method-cache-size* 2)))))
(declare (fixnum nargs))
(dotimes (i nargs)
(declare (fixnum i))
(setf (si:gfun-spec-how-ref gfun i) nil))
gfun))
;;; early version used during bootstrap
(defun ensure-generic-function (name &key lambda-list)
(let (gfun)
(unless (and (fboundp name)
(si:gfunp (setq gfun (fdefinition name))))
;; create a fake standard-generic-function object:
(let ((gf-object (si:allocate-raw-instance (find-class 't) 8)))
(declare (type standard-object gf-object))
;; create a new gfun
(setq gfun (make-gfun name lambda-list))
(si:instance-set gf-object 0 lambda-list) ; lambda-list
(si:instance-set gf-object 1 'default) ; argument-precedence-order
(si:instance-set gf-object 2 'standard) ; method-combination
(si:instance-set gf-object 3 nil) ; method-combination-arguments
(si:instance-set gf-object 5 nil) ; documentation
(si:instance-set gf-object 6 gfun) ; gfun
(si:instance-set gf-object 7 nil) ; methods
(si:gfun-instance-set gfun gf-object)
(setf (fdefinition name) gfun)))
(si:gfun-instance gfun)))