PageRenderTime 55ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/src/clos-class3.lisp

https://github.com/ynd/clisp-branch--ynd-devel
Lisp | 2716 lines | 1988 code | 132 blank | 596 comment | 48 complexity | 03a0e13ccff506b1a2c2cfd9176a14a2 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. ;;;; Common Lisp Object System for CLISP
  2. ;;;; Class metaobjects
  3. ;;;; Part 3: Class definition and redefinition.
  4. ;;;; Bruno Haible 21.8.1993 - 2004
  5. ;;;; Sam Steingold 1998 - 2007
  6. ;;;; German comments translated into English: Stefan Kain 2002-04-08
  7. (in-package "CLOS")
  8. ;; Wipe out all traces of an earlier loaded CLOS.
  9. (eval-when (load eval)
  10. (do-all-symbols (s) (remprop s 'CLOSCLASS)))
  11. ;; CLtL2 28.1.4., ANSI CL 4.3.7. Integrating Types and Classes
  12. (defun subclassp (class1 class2)
  13. (unless (>= (class-initialized class1) 4) (finalize-inheritance class1))
  14. (values
  15. (gethash class2 (class-all-superclasses class1)))) ; T or (default) NIL
  16. ;; Continue bootstrapping.
  17. (%defclos
  18. ;; distinctive marks for CLASS-P
  19. *<standard-class>-class-version*
  20. *<structure-class>-class-version*
  21. *<built-in-class>-class-version*
  22. 'defined-class
  23. 'class
  24. ;; built-in-classes for CLASS-OF
  25. (vector 'array 'bit-vector 'character 'complex 'cons 'float 'function
  26. 'hash-table 'integer 'list 'null 'package 'pathname
  27. #+LOGICAL-PATHNAMES 'logical-pathname
  28. 'random-state 'ratio 'readtable
  29. 'stream 'file-stream 'synonym-stream 'broadcast-stream
  30. 'concatenated-stream 'two-way-stream 'echo-stream 'string-stream
  31. 'string 'symbol 't 'vector))
  32. ;; Bootstrapping support.
  33. (defun replace-class-version (class class-version)
  34. (replace class-version (class-current-version class))
  35. (setf (class-current-version class) class-version))
  36. ;;; -------------------------------- DEFCLASS --------------------------------
  37. (defmacro defclass (&whole whole-form
  38. name superclass-specs slot-specs &rest options)
  39. (unless (symbolp name)
  40. (error-of-type 'ext:source-program-error
  41. :form whole-form
  42. :detail name
  43. (TEXT "~S: class name ~S should be a symbol")
  44. 'defclass name))
  45. (let* ((superclass-forms
  46. (progn
  47. (unless (listp superclass-specs)
  48. (error-of-type 'ext:source-program-error
  49. :form whole-form
  50. :detail superclass-specs
  51. (TEXT "~S ~S: expecting list of superclasses instead of ~S")
  52. 'defclass name superclass-specs))
  53. (mapcar #'(lambda (superclass)
  54. (unless (symbolp superclass)
  55. (error-of-type 'ext:source-program-error
  56. :form whole-form
  57. :detail superclass
  58. (TEXT "~S ~S: superclass name ~S should be a symbol")
  59. 'defclass name superclass))
  60. `',superclass)
  61. superclass-specs)))
  62. (accessor-method-decl-forms '())
  63. (accessor-function-decl-forms '())
  64. (generic-accessors nil) (generic-accessors-arg 'T)
  65. (slot-forms
  66. (let ((slot-names '()))
  67. (unless (listp slot-specs)
  68. (error-of-type 'ext:source-program-error
  69. :form whole-form
  70. :detail slot-specs
  71. (TEXT "~S ~S: expecting list of slot specifications instead of ~S")
  72. 'defclass name slot-specs))
  73. (when (and (oddp (length slot-specs)) (cdr slot-specs)
  74. (do ((l (cdr slot-specs) (cddr l)))
  75. ((endp l) t)
  76. (unless (keywordp (car l))
  77. (return nil))))
  78. ;; Typical beginner error: Omission of the parentheses around the
  79. ;; slot-specs. Probably someone who knows DEFSTRUCT and uses
  80. ;; DEFCLASS for the first time.
  81. (clos-warning (TEXT "~S ~S: Every second slot name is a keyword, and these slots have no options. If you want to define a slot with options, you need to enclose all slot specifications in parentheses: ~S, not ~S.")
  82. 'defclass name (list slot-specs) slot-specs))
  83. (mapcar #'(lambda (slot-spec)
  84. (let ((slot-name slot-spec) (slot-options '()))
  85. (when (consp slot-spec)
  86. (setq slot-name (car slot-spec)
  87. slot-options (cdr slot-spec)))
  88. (unless (symbolp slot-name)
  89. (error-of-type 'ext:source-program-error
  90. :form whole-form
  91. :detail slot-name
  92. (TEXT "~S ~S: slot name ~S should be a symbol")
  93. 'defclass name slot-name))
  94. (if (memq slot-name slot-names)
  95. (error-of-type 'ext:source-program-error
  96. :form whole-form
  97. :detail slot-names
  98. (TEXT "~S ~S: There may be only one direct slot with the name ~S.")
  99. 'defclass name slot-name)
  100. (push slot-name slot-names))
  101. (let ((readers '())
  102. (writers '())
  103. (allocations '())
  104. (initargs '())
  105. (initform nil) (initfunction nil)
  106. (types '())
  107. (documentation nil)
  108. (user-defined-args nil))
  109. (when (oddp (length slot-options))
  110. (error-of-type 'ext:source-program-error
  111. :form whole-form
  112. :detail slot-options
  113. (TEXT "~S ~S: slot options for slot ~S must come in pairs")
  114. 'defclass name slot-name))
  115. (do ((optionsr slot-options (cddr optionsr)))
  116. ((atom optionsr))
  117. (let ((optionkey (first optionsr))
  118. (argument (second optionsr)))
  119. (case optionkey
  120. (:READER
  121. (unless (and (symbolp argument) argument)
  122. (error-of-type 'ext:source-program-error
  123. :form whole-form
  124. :detail argument
  125. (TEXT "~S ~S, slot option for slot ~S: ~S is not a non-NIL symbol")
  126. 'defclass name slot-name argument))
  127. (push argument readers))
  128. (:WRITER
  129. (unless (function-name-p argument)
  130. (error-of-type 'ext:source-program-error
  131. :form whole-form
  132. :detail argument
  133. (TEXT "~S ~S, slot option for slot ~S: ~S is not a function name")
  134. 'defclass name slot-name argument))
  135. (push argument writers))
  136. (:ACCESSOR
  137. (unless (and (symbolp argument) argument)
  138. (error-of-type 'ext:source-program-error
  139. :form whole-form
  140. :detail argument
  141. (TEXT "~S ~S, slot option for slot ~S: ~S is not a non-NIL symbol")
  142. 'defclass name slot-name argument))
  143. (push argument readers)
  144. (push `(SETF ,argument) writers))
  145. (:ALLOCATION
  146. (unless (symbolp argument)
  147. (error-of-type 'ext:source-program-error
  148. :form whole-form
  149. :detail argument
  150. (TEXT "~S ~S, slot option ~S for slot ~S: ~S is not a symbol")
  151. 'defclass name ':allocation slot-name argument))
  152. (when allocations
  153. (error-of-type 'ext:source-program-error
  154. :form whole-form
  155. :detail slot-options
  156. (TEXT "~S ~S, slot option ~S for slot ~S may only be given once")
  157. 'defclass name ':allocation slot-name))
  158. (setq allocations (list argument)))
  159. (:INITARG
  160. (unless (symbolp argument)
  161. (error-of-type 'ext:source-program-error
  162. :form whole-form
  163. :detail argument
  164. (TEXT "~S ~S, slot option for slot ~S: ~S is not a symbol")
  165. 'defclass name slot-name argument))
  166. (push argument initargs))
  167. (:INITFORM
  168. (when initform
  169. (error-of-type 'ext:source-program-error
  170. :form whole-form
  171. :detail slot-options
  172. (TEXT "~S ~S, slot option ~S for slot ~S may only be given once")
  173. 'defclass name ':initform slot-name))
  174. (setq initform `(QUOTE ,argument)
  175. initfunction (make-initfunction-form argument slot-name)))
  176. (:TYPE
  177. (when types
  178. (error-of-type 'ext:source-program-error
  179. :form whole-form
  180. :detail slot-options
  181. (TEXT "~S ~S, slot option ~S for slot ~S may only be given once")
  182. 'defclass name ':type slot-name))
  183. (setq types (list argument)))
  184. (:DOCUMENTATION
  185. (when documentation
  186. (error-of-type 'ext:source-program-error
  187. :form whole-form
  188. :detail slot-options
  189. (TEXT "~S ~S, slot option ~S for slot ~S may only be given once")
  190. 'defclass name ':documentation slot-name))
  191. (unless (stringp argument)
  192. (error-of-type 'ext:source-program-error
  193. :form whole-form
  194. :detail argument
  195. (TEXT "~S ~S, slot option for slot ~S: ~S is not a string")
  196. 'defclass name slot-name argument))
  197. (setq documentation argument))
  198. ((:NAME :READERS :WRITERS :INITARGS :INITFUNCTION)
  199. ;; These are valid initialization keywords for
  200. ;; <direct-slot-definition>, but nevertheless
  201. ;; not valid DEFCLASS slot options.
  202. (error-of-type 'ext:source-program-error
  203. :form whole-form
  204. :detail optionkey
  205. (TEXT "~S ~S, slot option for slot ~S: ~S is not a valid slot option")
  206. 'defclass name slot-name optionkey))
  207. (t
  208. (if (symbolp optionkey)
  209. (let ((acons (assoc optionkey user-defined-args)))
  210. (if acons
  211. (push argument (cdr acons))
  212. (push (list optionkey argument) user-defined-args)))
  213. (error-of-type 'ext:source-program-error
  214. :form whole-form
  215. :detail optionkey
  216. (TEXT "~S ~S, slot option for slot ~S: ~S is not a valid slot option")
  217. 'defclass name slot-name optionkey))))))
  218. (setq readers (nreverse readers))
  219. (setq writers (nreverse writers))
  220. (setq user-defined-args (nreverse user-defined-args))
  221. (let ((type (if types (first types) 'T)))
  222. (dolist (funname readers)
  223. (push `(DECLAIM-METHOD ,funname ((OBJECT ,name)))
  224. accessor-method-decl-forms)
  225. (push `(PROCLAIM '(FUNCTION ,funname (,name) ,type))
  226. accessor-function-decl-forms)
  227. (push `(SYSTEM::EVAL-WHEN-COMPILE (SYSTEM::C-DEFUN ',funname (SYSTEM::LAMBDA-LIST-TO-SIGNATURE '(OBJECT))))
  228. accessor-function-decl-forms))
  229. (dolist (funname writers)
  230. (push `(DECLAIM-METHOD ,funname (NEW-VALUE (OBJECT ,name)))
  231. accessor-method-decl-forms)
  232. (push `(PROCLAIM '(FUNCTION ,funname (,type ,name) ,type))
  233. accessor-function-decl-forms)
  234. (push `(SYSTEM::EVAL-WHEN-COMPILE (SYSTEM::C-DEFUN ',funname (SYSTEM::LAMBDA-LIST-TO-SIGNATURE '(NEW-VALUE OBJECT))))
  235. accessor-function-decl-forms)))
  236. `(LIST
  237. :NAME ',slot-name
  238. ,@(when readers `(:READERS ',readers))
  239. ,@(when writers `(:WRITERS ',writers))
  240. ,@(when allocations `(:ALLOCATION ',(first allocations)))
  241. ,@(when initargs `(:INITARGS ',(nreverse initargs)))
  242. ,@(when initform `(:INITFORM ,initform :INITFUNCTION ,initfunction))
  243. ,@(when types `(:TYPE ',(first types)))
  244. ,@(when documentation `(:DOCUMENTATION ',documentation))
  245. ,@(when user-defined-args
  246. ;; For error-checking purposes:
  247. `('DEFCLASS-FORM ',whole-form))
  248. ,@(mapcan #'(lambda (option)
  249. (list `',(car option)
  250. ;; If there are multiple occurrences
  251. ;; of the same option, the values are
  252. ;; passed as a list. Otherwise a single
  253. ;; value is passed (not a 1-element list)!
  254. `',(if (cddr option)
  255. (nreverse (cdr option))
  256. (cadr option))))
  257. user-defined-args)))))
  258. slot-specs)))
  259. (metaclass nil) (metaclass-arg nil)
  260. (direct-default-initargs nil)
  261. (documentation nil)
  262. (user-defined-args nil))
  263. (dolist (option options)
  264. (block nil
  265. (when (listp option)
  266. (let ((optionkey (first option)))
  267. (when (case optionkey
  268. (:METACLASS metaclass)
  269. (:DEFAULT-INITARGS direct-default-initargs)
  270. (:DOCUMENTATION documentation))
  271. (error-of-type 'ext:source-program-error
  272. :form whole-form
  273. :detail options
  274. (TEXT "~S ~S, option ~S may only be given once")
  275. 'defclass name optionkey))
  276. (case optionkey
  277. (:METACLASS
  278. (when (eql (length option) 2)
  279. (let ((argument (second option)))
  280. (unless (symbolp argument)
  281. (error-of-type 'ext:source-program-error
  282. :form whole-form
  283. :detail argument
  284. (TEXT "~S ~S, option ~S: ~S is not a symbol")
  285. 'defclass name option argument))
  286. (setq metaclass-arg argument)
  287. (setq metaclass `(FIND-CLASS ',argument)))
  288. (return)))
  289. (:DEFAULT-INITARGS
  290. (let ((list (rest option)))
  291. (when (and (consp list) (null (cdr list)) (listp (car list)))
  292. (setq list (car list))
  293. (clos-warning (TEXT "~S ~S: option ~S should be written ~S")
  294. 'defclass name option (cons ':DEFAULT-INITARGS list)))
  295. (when (oddp (length list))
  296. (error-of-type 'ext:source-program-error
  297. :form whole-form
  298. :detail list
  299. (TEXT "~S ~S, option ~S: arguments must come in pairs")
  300. 'defclass name option))
  301. (setq direct-default-initargs
  302. `(:DIRECT-DEFAULT-INITARGS
  303. (LIST
  304. ,@(let ((arglist nil) (formlist nil))
  305. (do ((listr list (cddr listr)))
  306. ((atom listr))
  307. (unless (symbolp (first listr))
  308. (error-of-type 'ext:source-program-error
  309. :form whole-form
  310. :detail (first listr)
  311. (TEXT "~S ~S, option ~S: ~S is not a symbol")
  312. 'defclass name option (first listr)))
  313. (when (member (first listr) arglist)
  314. (error-of-type 'ext:source-program-error
  315. :form whole-form
  316. :detail list
  317. (TEXT "~S ~S, option ~S: ~S may only be given once")
  318. 'defclass name option (first listr)))
  319. (push (first listr) arglist)
  320. (push (second listr) formlist))
  321. (mapcan #'(lambda (arg form)
  322. `((LIST ',arg ',form ,(make-initfunction-form form arg))))
  323. (nreverse arglist) (nreverse formlist)))))))
  324. (return))
  325. (:DOCUMENTATION
  326. (when (eql (length option) 2)
  327. (let ((argument (second option)))
  328. (unless (stringp argument)
  329. (error-of-type 'ext:source-program-error
  330. :form whole-form
  331. :detail argument
  332. (TEXT "~S ~S, option ~S: ~S is not a string")
  333. 'defclass name option argument))
  334. (setq documentation
  335. `(:DOCUMENTATION ',argument)))
  336. (return)))
  337. ((:NAME :DIRECT-SUPERCLASSES :DIRECT-SLOTS :DIRECT-DEFAULT-INITARGS)
  338. ;; These are valid initialization keywords for <defined-class>,
  339. ;; but nevertheless not valid DEFCLASS options.
  340. (error-of-type 'ext:source-program-error
  341. :form whole-form
  342. :detail option
  343. (TEXT "~S ~S: invalid option ~S")
  344. 'defclass name option))
  345. (:GENERIC-ACCESSORS
  346. (when (eql (length option) 2)
  347. (let ((argument (second option)))
  348. (setq generic-accessors-arg argument)
  349. (setq generic-accessors `(:GENERIC-ACCESSORS ',argument))
  350. (return))))
  351. (T
  352. (when (symbolp optionkey)
  353. (when (assoc optionkey user-defined-args)
  354. (error-of-type 'ext:source-program-error
  355. :form whole-form
  356. :detail options
  357. (TEXT "~S ~S, option ~S may only be given once")
  358. 'defclass name optionkey))
  359. (push option user-defined-args)
  360. (return))))))
  361. (error-of-type 'ext:source-program-error
  362. :form whole-form
  363. :detail option
  364. (TEXT "~S ~S: invalid option ~S")
  365. 'defclass name option)))
  366. (setq user-defined-args (nreverse user-defined-args))
  367. (let ((metaclass-var (gensym))
  368. (metaclass-keywords-var (gensym)))
  369. `(LET ()
  370. (EVAL-WHEN (COMPILE LOAD EVAL)
  371. (LET* ((,metaclass-var ,(or metaclass '<STANDARD-CLASS>))
  372. ,@(if user-defined-args
  373. `((,metaclass-keywords-var
  374. ,(cond ((or (null metaclass) (eq metaclass-arg 'STANDARD-CLASS))
  375. '*<STANDARD-CLASS>-VALID-INITIALIZATION-KEYWORDS*)
  376. ((eq metaclass-arg 'FUNCALLABLE-STANDARD-CLASS)
  377. '*<FUNCALLABLE-STANDARD-CLASS>-VALID-INITIALIZATION-KEYWORDS*)
  378. (t `(CLASS-VALID-INITIALIZATION-KEYWORDS ,metaclass-var)))))))
  379. ;; Provide good error messages. The error message from
  380. ;; ENSURE-CLASS (actually MAKE-INSTANCE) later is unintelligible.
  381. ,@(if user-defined-args
  382. `((UNLESS (EQ ,metaclass-keywords-var 'T)
  383. ,@(mapcar #'(lambda (option)
  384. `(UNLESS (MEMBER ',(first option) ,metaclass-keywords-var)
  385. (ERROR-OF-TYPE 'EXT:SOURCE-PROGRAM-ERROR
  386. :FORM ',whole-form
  387. :DETAIL ',option
  388. (TEXT "~S ~S: invalid option ~S")
  389. 'DEFCLASS ',name ',option)))
  390. user-defined-args))))
  391. (APPLY #'ENSURE-CLASS
  392. ',name
  393. :DIRECT-SUPERCLASSES (LIST ,@superclass-forms)
  394. :DIRECT-SLOTS (LIST ,@slot-forms)
  395. :METACLASS ,metaclass-var
  396. ,@direct-default-initargs
  397. ,@documentation
  398. ,@generic-accessors
  399. ;; Pass user-defined initargs of the metaclass.
  400. ,@(mapcan #'(lambda (option)
  401. (list `',(first option) `',(rest option)))
  402. user-defined-args)
  403. (APPEND
  404. ;; Pass the default initargs of the metaclass, in
  405. ;; order to erase leftovers from the previous definition.
  406. ,(if metaclass
  407. `(MAPCAN #'(LAMBDA (X) (LIST (FIRST X) (FUNCALL (THIRD X))))
  408. (CLASS-DEFAULT-INITARGS ,metaclass-var))
  409. `',*<standard-class>-default-initargs*)
  410. (LIST
  411. ;; Here we use (unless ... '(... NIL)) because when a class
  412. ;; is being redefined, passing :DOCUMENTATION NIL to
  413. ;; ENSURE-CLASS means to erase the documentation string,
  414. ;; while nothing means to keep it! See MOP p. 57.
  415. ,@(unless direct-default-initargs '(:DIRECT-DEFAULT-INITARGS NIL))
  416. ,@(unless documentation '(:DOCUMENTATION NIL))
  417. ,@(unless generic-accessors '(:GENERIC-ACCESSORS 'T)))))))
  418. ,@(if generic-accessors-arg
  419. (nreverse accessor-method-decl-forms) ; the DECLAIM-METHODs
  420. (nreverse accessor-function-decl-forms)) ; the C-DEFUNs
  421. (FIND-CLASS ',name)))))
  422. ;; DEFCLASS execution:
  423. ;; The function responsible for a MAKE-INSTANCES-OBSOLETE call.
  424. (defvar *make-instances-obsolete-caller* 'make-instances-obsolete)
  425. (defun ensure-class-using-class-<t> (class name &rest all-keys
  426. &key (metaclass <standard-class>)
  427. (direct-superclasses '())
  428. (direct-slots '())
  429. (direct-default-initargs '())
  430. (documentation nil)
  431. (fixed-slot-locations nil)
  432. &allow-other-keys)
  433. (declare (ignore direct-slots direct-default-initargs documentation
  434. fixed-slot-locations))
  435. ;; Argument checks.
  436. (unless (symbolp name)
  437. (error (TEXT "~S: class name ~S should be a symbol")
  438. 'ensure-class-using-class name))
  439. (unless (defined-class-p metaclass)
  440. (if (symbolp metaclass)
  441. (setq metaclass
  442. (cond ((eq metaclass 'standard-class) <standard-class>) ; for bootstrapping
  443. (t (find-class metaclass))))
  444. (error (TEXT "~S for class ~S: metaclass ~S is neither a class or a symbol")
  445. 'ensure-class-using-class name metaclass)))
  446. (unless (or (eq metaclass <standard-class>) ; for bootstrapping
  447. (subclassp metaclass <defined-class>))
  448. (error (TEXT "~S for class ~S: metaclass ~S is not a subclass of CLASS")
  449. 'ensure-class-using-class name metaclass))
  450. (unless (proper-list-p direct-superclasses)
  451. (error (TEXT "~S for class ~S: The ~S argument should be a proper list, not ~S")
  452. 'ensure-class-using-class name ':direct-superclasses direct-superclasses))
  453. (unless (every #'(lambda (x)
  454. (or (defined-class-p x)
  455. (forward-reference-to-class-p x)
  456. (symbolp x)))
  457. direct-superclasses)
  458. (error (TEXT "~S for class ~S: The direct-superclasses list should consist of classes and symbols, not ~S")
  459. 'ensure-class-using-class name direct-superclasses))
  460. ;; Ignore the old class if the given name is not its "proper name".
  461. ;; (This is an ANSI CL requirement; it's not clear whether it belongs
  462. ;; here or in ENSURE-CLASS.)
  463. (when (and class (not (eq (class-name class) name)))
  464. (return-from ensure-class-using-class-<t>
  465. (apply #'ensure-class-using-class nil name all-keys)))
  466. ;; Decide whether to modify the given class or ignore it.
  467. (let ((a-semi-standard-class-p (or (eq metaclass <standard-class>)
  468. (subclassp metaclass <semi-standard-class>))))
  469. (when class
  470. (cond ((not (eq metaclass (class-of class)))
  471. ;; This can occur when mixing DEFSTRUCT and DEFCLASS.
  472. ;; MOP p. 48 says "If the class of the class argument is not the
  473. ;; same as the class specified by the :metaclass argument, an
  474. ;; error is signalled." But we can do better: ignore the old
  475. ;; class, warn and proceed. The old instances will thus keep
  476. ;; pointing to the old class.
  477. (clos-warning (TEXT "Cannot redefine ~S with a different metaclass ~S")
  478. class metaclass)
  479. (setq class nil))
  480. ((not a-semi-standard-class-p)
  481. ;; This can occur when redefining a class defined through
  482. ;; (DEFCLASS ... (:METACLASS STRUCTURE-CLASS)), which is
  483. ;; equivalent to re-executed DEFSTRUCT.
  484. ;; Only <semi-standard-class> subclasses support making instances
  485. ;; obsolete. Ignore the old class and proceed. The old instances
  486. ;; will thus keep pointing to the old class.
  487. (setq class nil)))
  488. (unless class
  489. (return-from ensure-class-using-class-<t>
  490. (apply #'ensure-class-using-class nil name all-keys))))
  491. ;; Preparation of class initialization arguments.
  492. (setq all-keys (copy-list all-keys))
  493. (remf all-keys ':metaclass)
  494. ;; See which direct superclasses are already defined.
  495. (setq direct-superclasses
  496. (mapcar #'(lambda (c)
  497. (if (defined-class-p c)
  498. c
  499. (let ((cn (if (forward-reference-to-class-p c) (class-name c) c)))
  500. (assert (symbolp cn))
  501. (if a-semi-standard-class-p
  502. ;; Need a class. Allocate a forward-referenced-class
  503. ;; if none is yet allocated.
  504. (or (get cn 'CLOSCLASS)
  505. (setf (get cn 'CLOSCLASS)
  506. (make-instance 'forward-referenced-class
  507. :name cn)))
  508. ;; Need a defined-class.
  509. (find-class cn)))))
  510. direct-superclasses))
  511. (if class
  512. ;; Modify the class and return the modified class.
  513. (apply #'reinitialize-instance ; => #'reinitialize-instance-<defined-class>
  514. class
  515. :direct-superclasses direct-superclasses
  516. all-keys)
  517. (setf (find-class name)
  518. (setq class
  519. (apply (cond ((eq metaclass <standard-class>)
  520. #'make-instance-<standard-class>)
  521. ((eq metaclass <funcallable-standard-class>)
  522. #'make-instance-<funcallable-standard-class>)
  523. ((eq metaclass <built-in-class>)
  524. #'make-instance-<built-in-class>)
  525. ((eq metaclass <structure-class>)
  526. #'make-instance-<structure-class>)
  527. (t #'make-instance))
  528. metaclass
  529. :name name
  530. :direct-superclasses direct-superclasses
  531. all-keys))))
  532. class))
  533. ;; Preliminary.
  534. (predefun ensure-class-using-class (class name &rest args
  535. &key (metaclass <standard-class>)
  536. (direct-superclasses '())
  537. (direct-slots '())
  538. (direct-default-initargs '())
  539. (documentation nil)
  540. (fixed-slot-locations nil)
  541. &allow-other-keys)
  542. (declare (ignore metaclass direct-superclasses direct-slots
  543. direct-default-initargs documentation fixed-slot-locations))
  544. (apply #'ensure-class-using-class-<t> class name args))
  545. ;; MOP p. 46
  546. (defun ensure-class (name &rest args
  547. &key (metaclass <standard-class>)
  548. (direct-superclasses '())
  549. (direct-slots '())
  550. (direct-default-initargs '())
  551. (documentation nil)
  552. (fixed-slot-locations nil)
  553. &allow-other-keys)
  554. (declare (ignore metaclass direct-superclasses direct-slots
  555. direct-default-initargs documentation fixed-slot-locations))
  556. (unless (symbolp name)
  557. (error (TEXT "~S: class name ~S should be a symbol")
  558. 'ensure-class name))
  559. (let ((result
  560. (apply #'ensure-class-using-class (find-class name nil) name args)))
  561. ; A check, to verify that user-defined methods on ensure-class-using-class
  562. ; work as they should.
  563. (unless (defined-class-p result)
  564. (error (TEXT "Wrong ~S result for ~S: not a class: ~S")
  565. 'ensure-class-using-class name result))
  566. result))
  567. ;; Preliminary.
  568. (predefun reader-method-class (class direct-slot &rest initargs)
  569. (declare (ignore class direct-slot initargs))
  570. <standard-reader-method>)
  571. (predefun writer-method-class (class direct-slot &rest initargs)
  572. (declare (ignore class direct-slot initargs))
  573. <standard-writer-method>)
  574. ;; ---------------------------- Class redefinition ----------------------------
  575. ;; When this is true, all safety checks about the metaclasses
  576. ;; of superclasses are omitted.
  577. (defparameter *allow-mixing-metaclasses* nil)
  578. (defun reinitialize-instance-<defined-class> (class &rest all-keys
  579. &key (name nil name-p)
  580. (direct-superclasses '() direct-superclasses-p)
  581. (direct-slots '() direct-slots-p)
  582. (direct-default-initargs '() direct-default-initargs-p)
  583. (documentation nil documentation-p)
  584. (fixed-slot-locations nil fixed-slot-locations-p)
  585. &allow-other-keys
  586. &aux (metaclass (class-of class)))
  587. (if (and (>= (class-initialized class) 4) ; already finalized?
  588. (subclassp class <metaobject>))
  589. ;; Things would go awry when we try to redefine <class> and similar.
  590. (clos-warning (TEXT "Redefining metaobject class ~S has no effect.") class)
  591. (progn
  592. (when direct-superclasses-p
  593. ;; Normalize the (class-direct-superclasses class) in the same way as
  594. ;; the direct-superclasses argument, so that we can compare the two
  595. ;; lists using EQUAL.
  596. (when (and (subclassp metaclass <standard-class>)
  597. (< (class-initialized class) 3))
  598. (do ((l (class-direct-superclasses class) (cdr l)))
  599. ((atom l))
  600. (let ((c (car l)))
  601. (unless (defined-class-p c)
  602. (let ((new-c
  603. (let ((cn (if (forward-reference-to-class-p c) (class-name c) c)))
  604. (assert (symbolp cn))
  605. ;; Need a class. Allocate a forward-referenced-class
  606. ;; if none is yet allocated.
  607. (or (get cn 'CLOSCLASS)
  608. (setf (get cn 'CLOSCLASS)
  609. (make-instance 'forward-referenced-class
  610. :name cn))))))
  611. (unless (eq new-c c)
  612. (when (defined-class-p new-c)
  613. ; changed from forward-referenced-class to defined-class
  614. (check-allowed-superclass class new-c))
  615. (setf (car l) new-c)
  616. (when (or (defined-class-p c) (forward-reference-to-class-p c))
  617. (remove-direct-subclass c class))
  618. (add-direct-subclass new-c class))))))))
  619. (when direct-slots-p
  620. ;; Convert the direct-slots to <direct-slot-definition> instances.
  621. (setq direct-slots (convert-direct-slots class direct-slots)))
  622. (when fixed-slot-locations-p
  623. ;; Convert from list to boolean.
  624. (when (consp fixed-slot-locations)
  625. (setq fixed-slot-locations (car fixed-slot-locations))))
  626. ;; Trivial changes (that can occur when loading the same code twice)
  627. ;; do not require updating the instances:
  628. ;; changed slot-options :initform, :documentation,
  629. ;; changed class-options :name, :default-initargs, :documentation.
  630. (if (or (and direct-superclasses-p
  631. (not (equal (or direct-superclasses (default-direct-superclasses class))
  632. (class-direct-superclasses class))))
  633. (and direct-slots-p
  634. (not (equal-direct-slots direct-slots (class-direct-slots class))))
  635. (and direct-default-initargs-p
  636. (not (equal-default-initargs direct-default-initargs
  637. (class-direct-default-initargs class))))
  638. (and fixed-slot-locations-p
  639. (not (eq fixed-slot-locations (class-fixed-slot-locations class)))))
  640. ;; Instances have to be updated:
  641. (let* ((was-finalized (>= (class-initialized class) 6))
  642. (must-be-finalized
  643. (and was-finalized
  644. (some #'class-instantiated (list-all-finalized-subclasses class))))
  645. (old-direct-superclasses (class-direct-superclasses class))
  646. (old-direct-accessors (class-direct-accessors class))
  647. (old-class-precedence-list (and was-finalized (class-precedence-list class)))
  648. old-class)
  649. ;; ANSI CL 4.3.6. Remove accessor methods created by old DEFCLASS.
  650. (remove-accessor-methods old-direct-accessors)
  651. (setf (class-direct-accessors class) '())
  652. ;; Clear the cached prototype.
  653. (setf (class-prototype class) nil)
  654. ;; Declare all instances as obsolete, and backup the class object.
  655. (let ((old-version (class-current-version class))
  656. (*make-instances-obsolete-caller* 'defclass))
  657. (make-instances-obsolete class)
  658. (setq old-class (cv-class old-version)))
  659. (locally (declare (compile))
  660. (sys::%handler-bind
  661. #'(lambda ()
  662. (apply #'shared-initialize
  663. ; => #'shared-initialize-<built-in-class>
  664. ; #'shared-initialize-<standard-class>
  665. ; #'shared-initialize-<structure-class>
  666. class nil
  667. `(,@(if direct-slots-p
  668. (list 'direct-slots direct-slots) '())
  669. ,@all-keys))
  670. ;; If the class could be finalized (although not a "must"),
  671. ;; keep it finalized and don't unfinalize it.
  672. (when (>= (class-initialized class) 6)
  673. (setq must-be-finalized t))
  674. (update-subclasses-for-redefined-class
  675. class was-finalized must-be-finalized
  676. old-direct-superclasses))
  677. ;; If an error occurs during the class redefinition,
  678. ;; switch back to the old definition, so that existing
  679. ;; instances can continue to be used.
  680. 'ERROR #'(lambda (condition)
  681. (declare (ignore condition))
  682. (let ((tmp-direct-superclasses (class-direct-superclasses class)))
  683. ;; Restore the class using the backup copy.
  684. (let ((new-version (class-current-version class)))
  685. (dotimes (i (sys::%record-length class))
  686. (setf (sys::%record-ref class i) (sys::%record-ref old-class i)))
  687. (setf (class-current-version class) new-version))
  688. ;; Restore the direct-subclasses pointers.
  689. (dolist (super tmp-direct-superclasses)
  690. (remove-direct-subclass-internal super class))
  691. (dolist (super old-direct-superclasses)
  692. (add-direct-subclass-internal super class))
  693. ;; Restore the finalized-direct-subclasses pointers.
  694. (dolist (super tmp-direct-superclasses)
  695. (when (semi-standard-class-p super)
  696. (remove-finalized-direct-subclass super class)))
  697. (when (>= (class-initialized class) 6)
  698. (dolist (super old-direct-superclasses)
  699. (when (semi-standard-class-p super)
  700. (add-finalized-direct-subclass super class))))
  701. ;; Restore the accessor methods.
  702. (add-accessor-methods old-direct-accessors)
  703. (setf (class-direct-accessors class) old-direct-accessors)))))
  704. (let ((new-class-precedence-list
  705. (and (>= (class-initialized class) 6) (class-precedence-list class))))
  706. (unless (equal old-class-precedence-list new-class-precedence-list)
  707. (update-subclass-instance-specializer-generic-functions class)
  708. (update-subclass-cpl-specializer-generic-functions class
  709. old-class-precedence-list new-class-precedence-list)))
  710. (install-class-direct-accessors class))
  711. ;; Instances don't need to be updated:
  712. (progn
  713. (when name-p
  714. ;; Store new name:
  715. (setf (class-classname class) name))
  716. (when direct-slots-p
  717. ;; Store new slot-inits:
  718. (do ((l-old (class-direct-slots class) (cdr l-old))
  719. (l-new direct-slots (cdr l-new)))
  720. ((null l-new))
  721. (let ((old (car l-old))
  722. (new (car l-new)))
  723. (setf (slot-definition-initform old) (slot-definition-initform new))
  724. (setf (slot-definition-initfunction old) (slot-definition-initfunction new))
  725. (setf (slot-definition-documentation old) (slot-definition-documentation new)))))
  726. (when direct-default-initargs-p
  727. ;; Store new default-initargs:
  728. (do ((l-old (class-direct-default-initargs class) (cdr l-old))
  729. (l-new direct-default-initargs (cdr l-new)))
  730. ((null l-new))
  731. (let ((old (cdar l-old))
  732. (new (cdar l-new)))
  733. ;; Move initform and initfunction from new destructively into
  734. ;; the old one:
  735. (setf (car old) (car new))
  736. (setf (cadr old) (cadr new)))))
  737. (when documentation-p
  738. ;; Store new documentation:
  739. (setf (class-documentation class) documentation))
  740. ;; NB: These modifications are automatically inherited by the
  741. ;; subclasses of class! Due to <inheritable-slot-definition-initer>
  742. ;; and <inheritable-slot-definition-doc>.
  743. ;; No need to call (install-class-direct-accessors class) here.
  744. ) )
  745. ;; Try to finalize it (mop-cl-reinit-mo, bug [ 1526448 ])
  746. (unless *allow-mixing-metaclasses* ; for gray.lisp
  747. (when (finalizable-p class)
  748. (finalize-inheritance class)))
  749. ;; Notification of listeners:
  750. (map-dependents class
  751. #'(lambda (dependent)
  752. (apply #'update-dependent class dependent all-keys)))
  753. ) )
  754. class)
  755. (defun equal-direct-slots (slots1 slots2)
  756. (or (and (null slots1) (null slots2))
  757. (and (consp slots1) (consp slots2)
  758. (equal-direct-slot (first slots1) (first slots2))
  759. (equal-direct-slots (rest slots1) (rest slots2)))))
  760. (defun equal-default-initargs (initargs1 initargs2)
  761. (or (and (null initargs1) (null initargs2))
  762. (and (consp initargs1) (consp initargs2)
  763. (eq (car (first initargs1)) (car (first initargs2)))
  764. (equal-default-initargs (cdr initargs1) (cdr initargs2)))))
  765. (defun map-dependents-<defined-class> (class function)
  766. (dolist (dependent (class-listeners class))
  767. (funcall function dependent)))
  768. ;; ------------------- General routines for <defined-class> -------------------
  769. ;; Preliminary.
  770. (predefun class-name (class)
  771. (class-classname class))
  772. ;; Returns the list of implicit direct superclasses when none was specified.
  773. (defun default-direct-superclasses (class)
  774. (cond ((typep class <standard-class>) (list <standard-object>))
  775. ((typep class <funcallable-standard-class>) (list <funcallable-standard-object>))
  776. ((typep class <structure-class>) (list <structure-object>))
  777. (t '())))
  778. (defun check-metaclass-mix (name direct-superclasses metaclass-test metaclass)
  779. (unless *allow-mixing-metaclasses*
  780. (unless (every metaclass-test direct-superclasses)
  781. (error-of-type 'error
  782. (TEXT "(~S ~S): superclass ~S should be of class ~S")
  783. 'DEFCLASS name (find-if-not metaclass-test direct-superclasses)
  784. metaclass))))
  785. ;; Preliminary.
  786. (predefun validate-superclass (class superclass)
  787. (or ;; Green light if class and superclass belong to the same metaclass.
  788. (eq (sys::%record-ref class 0) (sys::%record-ref superclass 0))
  789. ;; Green light also if class is a funcallable-standard-class and
  790. ;; superclass is a standard-class.
  791. (and (eq (sys::%record-ref class 0) *<funcallable-standard-class>-class-version*)
  792. (eq (sys::%record-ref superclass 0) *<standard-class>-class-version*))
  793. ;; Other than that, only <standard-object> and <structure-object> can
  794. ;; inherit from <t> without belonging to the same metaclass.
  795. (and (eq superclass <t>)
  796. (memq (class-classname class) '(standard-object structure-object)))
  797. ;; And only <funcallable-standard-object> can inherit from <function>
  798. ;; without belonging to the same metaclass.
  799. (and (eq superclass <function>)
  800. (eq (class-classname class) 'funcallable-standard-object))))
  801. (defun check-allowed-superclass (class superclass)
  802. (unless (validate-superclass class superclass)
  803. (error (TEXT "(~S ~S) for class ~S: ~S does not allow ~S to become a subclass of ~S. You may define a method on ~S to allow this.")
  804. 'initialize-instance 'class (class-classname class) 'validate-superclass class superclass
  805. 'validate-superclass)))
  806. ;;; The direct-subclasses slot can be either
  807. ;;; - NIL or a weak-list (for saving memory when there are few subclasses), or
  808. ;;; - a weak-hash-table (for speed when there are many subclasses).
  809. #|
  810. ;; Adds a class to the list of direct subclasses.
  811. (defun add-direct-subclass (class subclass) ...)
  812. ;; Removes a class from the list of direct subclasses.
  813. (defun remove-direct-subclass (class subclass) ...)
  814. ;; Returns the currently existing direct subclasses, as a freshly consed list.
  815. (defun list-direct-subclasses (class) ...)
  816. |#
  817. (def-weak-set-accessors class-direct-subclasses-table defined-class
  818. add-direct-subclass-internal
  819. remove-direct-subclass-internal
  820. list-direct-subclasses)
  821. ;; Preliminary.
  822. (predefun add-direct-subclass (class subclass)
  823. (add-direct-subclass-internal class subclass))
  824. (predefun remove-direct-subclass (class subclass)
  825. (remove-direct-subclass-internal class subclass))
  826. (predefun class-direct-subclasses (class)
  827. (list-direct-subclasses class))
  828. (defun checked-class-direct-subclasses (class)
  829. (let ((result (class-direct-subclasses class)))
  830. ; Some checks, to guarantee that user-defined methods on
  831. ; class-direct-subclasses don't break our CLOS.
  832. (unless (proper-list-p result)
  833. (error (TEXT "Wrong ~S result for class ~S: not a proper list: ~S")
  834. 'class-direct-subclasses (class-name class) result))
  835. (dolist (c result)
  836. (unless (defined-class-p c)
  837. (error (TEXT "Wrong ~S result for class ~S: list element is not a class: ~S")
  838. 'class-direct-subclasses (class-name class) c))
  839. (unless (memq class (class-direct-superclasses c))
  840. (error (TEXT "Wrong ~S result for class ~S: ~S is not a direct superclass of ~S")
  841. 'class-direct-subclasses (class-name class) class c)))
  842. result))
  843. (defun update-subclasses-sets (class old-direct-superclasses new-direct-superclasses)
  844. (unless (equal old-direct-superclasses new-direct-superclasses)
  845. (let ((removed-direct-superclasses
  846. (set-difference old-direct-superclasses new-direct-superclasses))
  847. (added-direct-superclasses
  848. (set-difference new-direct-superclasses old-direct-superclasses)))
  849. (dolist (super removed-direct-superclasses)
  850. (remove-direct-subclass super class))
  851. (dolist (super added-direct-superclasses)
  852. (add-direct-subclass super class)))))
  853. ;; ----------------------------------------------------------------------------
  854. ;; CLtL2 28.1.5., ANSI CL 4.3.5. Determining the Class Precedence List
  855. ;; The set of all classes forms a directed graph: Class C is located
  856. ;; below the direct superclasses of C. This graph is acyclic, because
  857. ;; at the moment of definition of the class C all direct superclasses must
  858. ;; already be present.
  859. ;; Hence, one can use Noether Induction (Induction from above to below in
  860. ;; the class graph) .
  861. ;; For a class C let DS(n) be the list of all direct superclasses of C.
  862. ;; The set of all superclasses (incl. C itself) is inductively defined as
  863. ;; S(C) := {C} union union_{D in DS(C)} S(D).
  864. ;; In other words:
  865. ;; S(C) = { C_n : C_n in DS(C_{n-1}), ..., C_1 in DS(C_0), C_0 = C }
  866. ;; Lemma 1: (a) C in S(C).
  867. ;; (b) DS(C) subset S(C).
  868. ;; (c) D in DS(C) ==> S(D) subset S(C).
  869. ;; (d) D in S(C) ==> S(D) subset S(C).
  870. ;; proof: (a) follows from the definition.
  871. ;; (b) from (a) and from the definition.
  872. ;; (c) from the definition.
  873. ;; (d) from (c) with fixed D via induction over C.
  874. ;; The CPL of a class C is one order of set S(C).
  875. ;; If CPL(C) = (... D1 ... D2 ...), one writes D1 < D2.
  876. ;; The relation introduc…

Large files files are truncated, but you can click here to view the full file