changelog shortlog graph tags branches changeset files file revisions raw help

Mercurial > core / annotate lisp/lib/obj/meta/stealth.lisp

changeset 234: d7aa08025537
child: 8ddd89b5e264
author: Richard Westhaver <ellis@rwest.io>
date: Wed, 20 Mar 2024 22:51:48 -0400
permissions: -rw-r--r--
description: cry, obj/meta, ffi/magick
234
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
1
 ;;; obj/meta/stealth.lisp --- Stealth Mixin
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
2
 
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
3
 ;;
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
4
 
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
5
 ;;; Code:
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
6
 (in-package :obj/meta/stealth)
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
7
 
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
8
 ;;;; The following hack is due to Gilbert Baumann.  It allows us to
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
9
 ;;;; dynamically mix in classes into a class without the latter being
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
10
 ;;;; aware of it.
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
11
 
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
12
 ;;; Mixins are not intended to be directly instantiated, and instead are used as superclasses to "normal" classes in order to capture common things between several "normal" classes.
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
13
 
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
14
 ;;; First of all we need to keep track of added mixins, we use a hash
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
15
 ;;; table here. Better would be to stick this information to the
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
16
 ;;; victim class itself.
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
17
 
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
18
 (defvar *stealth-mixins* (make-hash-table))
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
19
 
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
20
 (defmacro class-stealth-mixins (class)
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
21
   `(gethash ,class *stealth-mixins*))
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
22
 
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
23
 (defun add-mixin (mixin-name victim-class)
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
24
   "Add the mixin to the superclasses of the victim"
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
25
   (ensure-class victim-class
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
26
 			   :direct-superclasses (adjoin mixin-name
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
27
 							(and (find-class victim-class nil)
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
28
 							     (class-direct-superclasses
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
29
 							      (find-class victim-class)))
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
30
 							:test #'class-equalp)
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
31
 			   :metaclass (class-of (find-class victim-class)))
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
32
 
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
33
   ;; Register it as a new mixin for the victim class
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
34
   (pushnew mixin-name (class-stealth-mixins victim-class))
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
35
 
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
36
   ;; When one wants to [re]define the victim class the new mixin
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
37
   ;; should be present too. We do this by 'patching' ensure-class:
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
38
   (defmethod ensure-class-using-class :around
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
39
       (class (name (eql victim-class))
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
40
        &rest arguments
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
41
        &key (direct-superclasses nil direct-superclasses-p)
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
42
        &allow-other-keys)
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
43
     (cond (direct-superclasses-p
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
44
            ;; Silently modify the super classes to include our new
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
45
            ;; mixin.
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
46
            (dolist (k (class-stealth-mixins name))
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
47
              (pushnew k direct-superclasses
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
48
                       :test #'class-equalp))
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
49
            (apply #'call-next-method class name
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
50
                   :direct-superclasses direct-superclasses
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
51
                   arguments))
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
52
           (t
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
53
            (call-next-method))))
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
54
   mixin-name)
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
55
 
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
56
 (defmacro define-stealth-mixin (name super-classes victim-class
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
57
                                 &rest for-defclass)
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
58
   "Like DEFCLASS but adds the newly defined class to the super classes
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
59
 of 'victim-class'."
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
60
   `(progn
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
61
      ;; First define the class we talk about
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
62
      (defclass ,name ,super-classes ,@for-defclass)
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
63
      ;; Add the class to the mixins of the victim
d7aa08025537 cry, obj/meta, ffi/magick
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
64
      (add-mixin ',name ',victim-class)))