Simplify and automate the creation of the basic classes in boot.lsp

This commit is contained in:
Juanjo Garcia-Ripoll 2012-04-26 12:20:16 +02:00
parent 1fc8af38ba
commit 803a1fb823
3 changed files with 104 additions and 122 deletions

View file

@ -11,6 +11,65 @@
(in-package "CLOS")
;;; ----------------------------------------------------------------------
;;; FROM AMOP:
;;;
;;; Metaobject Class Direct Superclasses
;;; standard-object (t)
;;; funcallable-standard-object (standard-object function)
;;; * metaobject (standard-object)
;;; * generic-function (metaobject funcallable-standard-object)
;;; standard-generic-function (generic-function)
;;; * method (metaobject)
;;; standard-method (method)
;;; * standard-accessor-method (standard-method)
;;; standard-reader-method (standard-accessor-method)
;;; standard-writer-method (standard-accessor-method)
;;; * method-combination (metaobject)
;;; * slot-definition (metaobject)
;;; * direct-slot-definition (slot-definition)
;;; * effective-slot-definition (slot-definition)
;;; * standard-slot-definition (slot-definition)
;;; standard-direct-slot-definition (standard-slot-definition direct-slot-definition)
;;; standard-effective-slot-definition (standard-slot-definition effective-slot-definition)
;;; * specializer (metaobject)
;;; eql-specializer (specializer)
;;; * class (specializer)
;;; built-in-class (class)
;;; forward-referenced-class (class)
;;; standard-class (class)
;;; funcallable-standard-class (class)
;;;
(eval-when (compile eval)
(defconstant +class-hierarchy+
'((t)
(standard-object
:direct-superclasses (t))
(metaobject
:direct-superclasses (standard-object))
(method-combination
:direct-superclasses (metaobject)
:direct-slots #.(remove-accessors +method-combination-slots+))
(specializer
:direct-superclasses (metaobject)
:direct-slots #.(remove-accessors +specializer-slots+))
(eql-specializer
:direct-superclasses (specializer)
:direct-slots #.(remove-accessors +eql-specializer-slots+))
(class
:direct-superclasses (specializer)
:direct-slots #.(remove-accessors +class-slots+))
(std-class
:direct-superclasses (class)
:direct-slots #.(remove-accessors +standard-class-slots+))
(standard-class
:direct-superclasses (std-class)
:direct-slots #.(remove-accessors +standard-class-slots+))
(funcallable-standard-class
:direct-superclasses (std-class)
:direct-slots #.(remove-accessors +standard-class-slots+)))))
;;; ----------------------------------------------------------------------
;;; Building the classes T, CLASS, STANDARD-OBJECT and STANDARD-CLASS.
;;;
@ -18,7 +77,9 @@
;;; DIRECT-SLOTS, etc are empty and therefore SLOT-VALUE does not work.
(defun make-empty-standard-class (name metaclass)
(let ((class (si:allocate-raw-instance nil metaclass #.(length +standard-class-slots+))))
(let ((class (or (find-class name nil)
(si:allocate-raw-instance nil metaclass
#.(length +standard-class-slots+)))))
(unless metaclass
(si:instance-class-set class class))
(setf (class-id class) name
@ -33,7 +94,7 @@
(eql-specializer-flag class) nil
(specializer-direct-methods class) nil
(specializer-direct-generic-functions class) nil
(find-class name) class)
(gethash name si::*class-name-hash-table*) class)
(unless (eq name 'T)
(setf (slot-table class) (make-hash-table :size 2)))
class))
@ -59,112 +120,30 @@
;; Notice that, due to circularity in the definition, STANDARD-CLASS has
;; itself as metaclass. MAKE-EMPTY-CLASS takes care of that.
;;
(let* ((standard-class (make-empty-standard-class 'STANDARD-CLASS nil))
(std-class (make-empty-standard-class 'STD-CLASS standard-class))
(standard-object (make-empty-standard-class 'STANDARD-OBJECT standard-class))
(funcallable-standard-class
(make-empty-standard-class 'FUNCALLABLE-STANDARD-CLASS
standard-class))
(metaobject (make-empty-standard-class 'METAOBJECT standard-class))
(method-combination (make-empty-standard-class 'METHOD-COMBINATION standard-class))
(specializer (make-empty-standard-class 'SPECIALIZER standard-class))
(eql-specializer (make-empty-standard-class 'EQL-SPECIALIZER standard-class))
(the-class (make-empty-standard-class 'CLASS standard-class))
(the-t (make-empty-standard-class 'T the-class)))
;; 2) STANDARD-CLASS and CLASS and others are classes with slots. Create a
;; hash table for them, so that SLOT-VALUE works. Notice that we
;; make a intentional mistake: CLASS and STANDARD-CLASS share the same
;; hashtable!!
(add-slots the-class '#.(remove-accessors +class-slots+))
(add-slots std-class #1='#.(remove-accessors +standard-class-slots+))
(add-slots standard-class #1#)
(add-slots funcallable-standard-class #1#)
(add-slots method-combination '#.(remove-accessors +method-combination-slots+))
(add-slots specializer '#.(remove-accessors +specializer-slots+))
(add-slots eql-specializer '#.(remove-accessors +eql-specializer-slots+))
;; 3) Fix the class hierarchy
;; FROM AMOP:
(let ((all-classes '#.+class-hierarchy+))
;;
;; Metaobject Class Direct Superclasses
;; standard-object (t)
;; funcallable-standard-object (standard-object function)
;; * metaobject (standard-object)
;; * generic-function (metaobject funcallable-standard-object)
;; standard-generic-function (generic-function)
;; * method (metaobject)
;; standard-method (method)
;; * standard-accessor-method (standard-method)
;; standard-reader-method (standard-accessor-method)
;; standard-writer-method (standard-accessor-method)
;; * method-combination (metaobject)
;; * slot-definition (metaobject)
;; * direct-slot-definition (slot-definition)
;; * effective-slot-definition (slot-definition)
;; * standard-slot-definition (slot-definition)
;; standard-direct-slot-definition (standard-slot-definition direct-slot-definition)
;; standard-effective-slot-definition (standard-slot-definition effective-slot-definition)
;; * specializer (metaobject)
;; eql-specializer (specializer)
;; * class (specializer)
;; built-in-class (class)
;; forward-referenced-class (class)
;; standard-class (class)
;; funcallable-standard-class (class)
;; 1) Create the classes, fix their inheritance chain and add their slots
;;
(setf (class-direct-superclasses the-t) nil
(class-direct-subclasses the-t) (list standard-object)
(class-direct-superclasses standard-object) (list the-t)
(class-direct-subclasses standard-object) (list metaobject)
(class-direct-superclasses metaobject) (list standard-object)
(class-direct-subclasses metaobject) (list specializer method-combination)
(class-direct-superclasses method-combination) (list metaobject)
(class-direct-superclasses specializer) (list metaobject)
(class-direct-subclasses specializer) (list the-class eql-specializer)
(class-direct-superclasses eql-specializer) (list specializer)
(class-direct-superclasses the-class) (list specializer)
(class-direct-subclasses the-class) (list std-class)
(class-direct-superclasses std-class) (list the-class)
(class-direct-subclasses std-class) (list standard-class funcallable-standard-class)
(class-direct-superclasses standard-class) (list std-class)
(class-direct-superclasses funcallable-standard-class) (list std-class))
(si::instance-sig-set the-t)
(si::instance-sig-set standard-object)
(si::instance-sig-set metaobject)
(si::instance-sig-set method-combination)
(si::instance-sig-set specializer)
(si::instance-sig-set eql-specializer)
(si::instance-sig-set the-class)
(si::instance-sig-set std-class)
(si::instance-sig-set standard-class)
(si::instance-sig-set funcallable-standard-class)
;; 4) Fix the class precedence list
(let ((cpl (list std-class the-class metaobject standard-object the-t)))
(setf (class-precedence-list the-t)
(setf cpl (list the-t))
(class-precedence-list standard-object)
(setf cpl (list* standard-object cpl))
(class-precedence-list metaobject)
(setf cpl (list* metaobject cpl))
(class-precedence-list method-combination)
(list* method-combination cpl)
(class-precedence-list specializer)
(setf cpl (list* specializer cpl))
(class-precedence-list eql-specializer)
(list* eql-specializer cpl)
(class-precedence-list the-class)
(setf cpl (list* the-class cpl))
(class-precedence-list std-class)
(setf cpl (list* std-class cpl))
(class-precedence-list standard-class)
(list* standard-class cpl)
(class-precedence-list funcallable-standard-class)
(list* funcallable-standard-class cpl)))
;; 5) Generate accessors (In macros.lsp)
(loop with standard-class = (make-empty-standard-class 'standard-class nil)
for c in all-classes
for name = (first c)
for class = (make-empty-standard-class name standard-class)
for superclasses-names = (getf (rest c) :direct-superclasses)
for superclasses = (mapcar #'find-class superclasses-names)
for slots = (getf (rest c) :direct-slots)
do (setf (class-direct-superclasses class)
(loop for parent in superclasses
do (push class (class-direct-subclasses parent))
collect parent)
(class-precedence-list class)
(compute-clos-class-precedence-list class superclasses))
when slots
do (add-slots class slots))
;;
;; 3) Finalize
;;
(loop for c in all-classes
do (si::instance-sig-set (find-class (first c))))
)
(defconstant +the-t-class+ (find-class 't nil))

View file

@ -236,20 +236,23 @@
(let ((one-list (first l)))
(when (eq class (first one-list))
(setf (first l) (rest one-list)))))))
(if (endp (rest superclasses))
(let ((class (first superclasses)))
(list* new-class (class-precedence-list class)))
(multiple-value-bind (class-list precedence-lists)
(walk-supers superclasses)
(do ((cpl (list new-class)))
((null class-list)
(if precedence-lists (cycle-error new-class) (nreverse cpl)))
(let* ((candidates (free-elements class-list precedence-lists))
(next (next-element candidates cpl)))
(unless next
(cycle-error new-class))
(setf precedence-lists (delete-class next precedence-lists)
class-list (delete next class-list)
cpl (cons next cpl))))))))
(cond ((null superclasses)
(list new-class))
((endp (rest superclasses))
(let ((class (first superclasses)))
(list* new-class (class-precedence-list class))))
(t
(multiple-value-bind (class-list precedence-lists)
(walk-supers superclasses)
(do ((cpl (list new-class)))
((null class-list)
(if precedence-lists (cycle-error new-class) (nreverse cpl)))
(let* ((candidates (free-elements class-list precedence-lists))
(next (next-element candidates cpl)))
(unless next
(cycle-error new-class))
(setf precedence-lists (delete-class next precedence-lists)
class-list (delete next class-list)
cpl (cons next cpl)))))))))
;;; ----------------------------------------------------------------------

View file

@ -6,8 +6,8 @@
"src:clos;method.lsp"
"src:clos;slot.lsp"
"src:clos;combin.lsp"
"src:clos;boot.lsp"
"src:clos;defclass.lsp"
"src:clos;boot.lsp"
"src:clos;standard.lsp"
"src:clos;builtin.lsp"
"src:clos;change.lsp"