105237
|
1 ;;; eieio.el --- Enhanced Implementation of Emacs Interpreted Objects
|
|
2 ;;; or maybe Eric's Implementation of Emacs Intrepreted Objects
|
|
3
|
|
4 ;;; Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
|
|
5 ;;; 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
|
6
|
|
7 ;; Author: Eric M. Ludlam <zappo@gnu.org>
|
|
8 ;; Version: 0.2
|
|
9 ;; Keywords: OO, lisp
|
|
10
|
|
11 ;; This file is part of GNU Emacs.
|
|
12
|
|
13 ;; GNU Emacs is free software: you can redistribute it and/or modify
|
|
14 ;; it under the terms of the GNU General Public License as published by
|
|
15 ;; the Free Software Foundation, either version 3 of the License, or
|
|
16 ;; (at your option) any later version.
|
|
17
|
|
18 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
21 ;; GNU General Public License for more details.
|
|
22
|
|
23 ;; You should have received a copy of the GNU General Public License
|
|
24 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
|
25
|
|
26 ;;; Commentary:
|
|
27 ;;
|
|
28 ;; EIEIO is a series of Lisp routines which implements a subset of
|
|
29 ;; CLOS, the Common Lisp Object System. In addition, EIEIO also adds
|
|
30 ;; a few new features which help it integrate more strongly with the
|
|
31 ;; Emacs running environment.
|
|
32 ;;
|
|
33 ;; See eieio.texi for complete documentation on using this package.
|
|
34
|
|
35 ;; There is funny stuff going on with typep and deftype. This
|
|
36 ;; is the only way I seem to be able to make this stuff load properly.
|
|
37
|
|
38 ;; @TODO - fix :initform to be a form, not a quoted value
|
|
39 ;; @TODO - Prefix non-clos functions with `eieio-'.
|
|
40
|
|
41 ;;; Code:
|
|
42
|
|
43 (require 'cl)
|
|
44 (eval-when-compile (require 'eieio-comp))
|
|
45
|
|
46 (defvar eieio-version "1.2"
|
|
47 "Current version of EIEIO.")
|
|
48
|
|
49 (defun eieio-version ()
|
|
50 "Display the current version of EIEIO."
|
|
51 (interactive)
|
|
52 (message eieio-version))
|
|
53
|
|
54 (eval-and-compile
|
|
55 ;; About the above. EIEIO must process it's own code when it compiles
|
|
56 ;; itself, thus, by eval-and-compiling outselves, we solve the problem.
|
|
57
|
|
58 ;; Compatibility
|
|
59 (if (fboundp 'compiled-function-arglist)
|
|
60
|
|
61 ;; XEmacs can only access a compiled functions arglist like this:
|
|
62 (defalias 'eieio-compiled-function-arglist 'compiled-function-arglist)
|
|
63
|
|
64 ;; Emacs doesn't have this function, but since FUNC is a vector, we can just
|
|
65 ;; grab the appropriate element.
|
|
66 (defun eieio-compiled-function-arglist (func)
|
|
67 "Return the argument list for the compiled function FUNC."
|
|
68 (aref func 0))
|
|
69
|
|
70 )
|
|
71
|
|
72
|
|
73 ;;;
|
|
74 ;; Variable declarations.
|
|
75 ;;
|
|
76
|
|
77 (defvar eieio-hook nil
|
|
78 "*This hook is executed, then cleared each time `defclass' is called.")
|
|
79
|
|
80 (defvar eieio-error-unsupported-class-tags nil
|
|
81 "*Non nil to throw an error if an encountered tag us unsupported.
|
|
82 This may prevent classes from CLOS applications from being used with EIEIO
|
|
83 since EIEIO does not support all CLOS tags.")
|
|
84
|
|
85 (defvar eieio-skip-typecheck nil
|
|
86 "*If non-nil, skip all slot typechecking.
|
|
87 Set this to t permanently if a program is functioning well to get a
|
|
88 small speed increase. This variable is also used internally to handle
|
|
89 default setting for optimization purposes.")
|
|
90
|
|
91 (defvar eieio-optimize-primary-methods-flag t
|
|
92 "Non-nil means to optimize the method dispatch on primary methods.")
|
|
93
|
|
94 ;; State Variables
|
|
95 (defvar this nil
|
|
96 "Inside a method, this variable is the object in question.
|
|
97 DO NOT SET THIS YOURSELF unless you are trying to simulate friendly slots.
|
|
98
|
|
99 Note: Embedded methods are no longer supported. The variable THIS is
|
|
100 still set for CLOS methods for the sake of routines like
|
|
101 `call-next-method'")
|
|
102
|
|
103 (defvar scoped-class nil
|
|
104 "This is set to a class when a method is running.
|
|
105 This is so we know we are allowed to check private parts or how to
|
|
106 execute a `call-next-method'. DO NOT SET THIS YOURSELF!")
|
|
107
|
|
108 (defvar eieio-initializing-object nil
|
|
109 "Set to non-nil while initializing an object.")
|
|
110
|
|
111 (defconst eieio-unbound
|
|
112 (if (and (boundp 'eieio-unbound) (symbolp eieio-unbound))
|
|
113 eieio-unbound
|
|
114 (make-symbol "unbound"))
|
|
115 "Uninterned symbol representing an unbound slot in an object.")
|
|
116
|
|
117 ;; This is a bootstrap for eieio-default-superclass so it has a value
|
|
118 ;; while it is being built itself.
|
|
119 (defvar eieio-default-superclass nil)
|
|
120
|
|
121 (defconst class-symbol 1 "Class's symbol (self-referencing.).")
|
|
122 (defconst class-parent 2 "Class parent slot.")
|
|
123 (defconst class-children 3 "Class children class slot.")
|
|
124 (defconst class-symbol-obarray 4 "Obarray permitting fast access to variable position indexes.")
|
|
125 ;; @todo
|
|
126 ;; the word "public" here is leftovers from the very first version.
|
|
127 ;; Get rid of it!
|
|
128 (defconst class-public-a 5 "Class attribute index.")
|
|
129 (defconst class-public-d 6 "Class attribute defaults index.")
|
|
130 (defconst class-public-doc 7 "Class documentation strings for attributes.")
|
|
131 (defconst class-public-type 8 "Class type for a slot.")
|
|
132 (defconst class-public-custom 9 "Class custom type for a slot.")
|
|
133 (defconst class-public-custom-label 10 "Class custom group for a slot.")
|
|
134 (defconst class-public-custom-group 11 "Class custom group for a slot.")
|
|
135 (defconst class-public-printer 12 "Printer for a slot.")
|
|
136 (defconst class-protection 13 "Class protection for a slot.")
|
|
137 (defconst class-initarg-tuples 14 "Class initarg tuples list.")
|
|
138 (defconst class-class-allocation-a 15 "Class allocated attributes.")
|
|
139 (defconst class-class-allocation-doc 16 "Class allocated documentation.")
|
|
140 (defconst class-class-allocation-type 17 "Class allocated value type.")
|
|
141 (defconst class-class-allocation-custom 18 "Class allocated custom descriptor.")
|
|
142 (defconst class-class-allocation-custom-label 19 "Class allocated custom descriptor.")
|
|
143 (defconst class-class-allocation-custom-group 20 "Class allocated custom group.")
|
|
144 (defconst class-class-allocation-printer 21 "Class allocated printer for a slot.")
|
|
145 (defconst class-class-allocation-protection 22 "Class allocated protection list.")
|
|
146 (defconst class-class-allocation-values 23 "Class allocated value vector.")
|
|
147 (defconst class-default-object-cache 24
|
|
148 "Cache index of what a newly created object would look like.
|
|
149 This will speed up instantiation time as only a `copy-sequence' will
|
|
150 be needed, instead of looping over all the values and setting them
|
|
151 from the default.")
|
|
152 (defconst class-options 25
|
|
153 "Storage location of tagged class options.
|
|
154 Stored outright without modifications or stripping.")
|
|
155
|
|
156 (defconst class-num-slots 26
|
|
157 "Number of slots in the class definition object.")
|
|
158
|
|
159 (defconst object-class 1 "Index in an object vector where the class is stored.")
|
|
160 (defconst object-name 2 "Index in an object where the name is stored.")
|
|
161
|
|
162 (defconst method-static 0 "Index into :static tag on a method.")
|
|
163 (defconst method-before 1 "Index into :before tag on a method.")
|
|
164 (defconst method-primary 2 "Index into :primary tag on a method.")
|
|
165 (defconst method-after 3 "Index into :after tag on a method.")
|
|
166 (defconst method-num-lists 4 "Number of indexes into methods vector in which groups of functions are kept.")
|
|
167 (defconst method-generic-before 4 "Index into generic :before tag on a method.")
|
|
168 (defconst method-generic-primary 5 "Index into generic :primary tag on a method.")
|
|
169 (defconst method-generic-after 6 "Index into generic :after tag on a method.")
|
|
170 (defconst method-num-slots 7 "Number of indexes into a method's vector.")
|
|
171
|
|
172 ;; How to specialty compile stuff.
|
|
173 (autoload 'byte-compile-file-form-defmethod "eieio-comp"
|
|
174 "This function is used to byte compile methods in a nice way.")
|
|
175 (put 'defmethod 'byte-hunk-handler 'byte-compile-file-form-defmethod)
|
|
176
|
|
177 ;;; Important macros used in eieio.
|
|
178 ;;
|
|
179 (defmacro class-v (class)
|
|
180 "Internal: Return the class vector from the CLASS symbol."
|
|
181 ;; No check: If eieio gets this far, it's probably been checked already.
|
|
182 `(get ,class 'eieio-class-definition))
|
|
183
|
|
184 (defmacro class-p (class)
|
|
185 "Return t if CLASS is a valid class vector.
|
|
186 CLASS is a symbol."
|
|
187 ;; this new method is faster since it doesn't waste time checking lots of
|
|
188 ;; things.
|
|
189 `(condition-case nil
|
|
190 (eq (aref (class-v ,class) 0) 'defclass)
|
|
191 (error nil)))
|
|
192
|
|
193 (defmacro eieio-object-p (obj)
|
|
194 "Return non-nil if OBJ is an EIEIO object."
|
|
195 `(condition-case nil
|
|
196 (let ((tobj ,obj))
|
|
197 (and (eq (aref tobj 0) 'object)
|
|
198 (class-p (aref tobj object-class))))
|
|
199 (error nil)))
|
|
200 (defalias 'object-p 'eieio-object-p)
|
|
201
|
|
202 (defmacro class-constructor (class)
|
|
203 "Return the symbol representing the constructor of CLASS."
|
|
204 `(aref (class-v ,class) class-symbol))
|
|
205
|
|
206 (defmacro generic-p (method)
|
|
207 "Return t if symbol METHOD is a generic function.
|
|
208 Only methods have the symbol `eieio-method-obarray' as a property (which
|
|
209 contains a list of all bindings to that method type.)"
|
|
210 `(and (fboundp ,method) (get ,method 'eieio-method-obarray)))
|
|
211
|
|
212 (defun generic-primary-only-p (method)
|
|
213 "Return t if symbol METHOD is a generic function with only primary methods.
|
|
214 Only methods have the symbol `eieio-method-obarray' as a property (which
|
|
215 contains a list of all bindings to that method type.)
|
|
216 Methods with only primary implementations are executed in an optimized way."
|
|
217 (and (generic-p method)
|
|
218 (let ((M (get method 'eieio-method-tree)))
|
|
219 (and (< 0 (length (aref M method-primary)))
|
|
220 (not (aref M method-static))
|
|
221 (not (aref M method-before))
|
|
222 (not (aref M method-after))
|
|
223 (not (aref M method-generic-before))
|
|
224 (not (aref M method-generic-primary))
|
|
225 (not (aref M method-generic-after))))
|
|
226 ))
|
|
227
|
|
228 (defun generic-primary-only-one-p (method)
|
|
229 "Return t if symbol METHOD is a generic function with only primary methods.
|
|
230 Only methods have the symbol `eieio-method-obarray' as a property (which
|
|
231 contains a list of all bindings to that method type.)
|
|
232 Methods with only primary implementations are executed in an optimized way."
|
|
233 (and (generic-p method)
|
|
234 (let ((M (get method 'eieio-method-tree)))
|
|
235 (and (= 1 (length (aref M method-primary)))
|
|
236 (not (aref M method-static))
|
|
237 (not (aref M method-before))
|
|
238 (not (aref M method-after))
|
|
239 (not (aref M method-generic-before))
|
|
240 (not (aref M method-generic-primary))
|
|
241 (not (aref M method-generic-after))))
|
|
242 ))
|
|
243
|
|
244 (defmacro class-option-assoc (list option)
|
|
245 "Return from LIST the found OPTION. Nil if it doesn't exist."
|
|
246 `(car-safe (cdr (memq ,option ,list))))
|
|
247
|
|
248 (defmacro class-option (class option)
|
|
249 "Return the value stored for CLASS' OPTION.
|
|
250 Return nil if that option doesn't exist."
|
|
251 `(class-option-assoc (aref (class-v ,class) class-options) ',option))
|
|
252
|
|
253 (defmacro class-abstract-p (class)
|
|
254 "Return non-nil if CLASS is abstract.
|
|
255 Abstract classes cannot be instantiated."
|
|
256 `(class-option ,class :abstract))
|
|
257
|
|
258 (defmacro class-method-invocation-order (class)
|
|
259 "Return the invocation order of CLASS.
|
|
260 Abstract classes cannot be instantiated."
|
|
261 `(or (class-option ,class :method-invocation-order)
|
|
262 :breadth-first))
|
|
263
|
|
264
|
|
265 ;;; Defining a new class
|
|
266 ;;
|
|
267 (defmacro defclass (name superclass slots &rest options-and-doc)
|
|
268 "Define NAME as a new class derived from SUPERCLASS with SLOTS.
|
|
269 OPTIONS-AND-DOC is used as the class' options and base documentation.
|
|
270 SUPERCLASS is a list of superclasses to inherit from, with SLOTS
|
|
271 being the slots residing in that class definition. NOTE: Currently
|
|
272 only one slot may exist in SUPERCLASS as multiple inheritance is not
|
|
273 yet supported. Supported tags are:
|
|
274
|
|
275 :initform - initializing form
|
|
276 :initarg - tag used during initialization
|
|
277 :accessor - tag used to create a function to access this slot
|
|
278 :allocation - specify where the value is stored.
|
|
279 defaults to `:instance', but could also be `:class'
|
|
280 :writer - a function symbol which will `write' an object's slot
|
|
281 :reader - a function symbol which will `read' an object
|
|
282 :type - the type of data allowed in this slot (see `typep')
|
|
283 :documentation
|
|
284 - A string documenting use of this slot.
|
|
285
|
|
286 The following are extensions on CLOS:
|
|
287 :protection - Specify protection for this slot.
|
|
288 Defaults to `:public'. Also use `:protected', or `:private'
|
|
289 :custom - When customizing an object, the custom :type. Public only.
|
|
290 :label - A text string label used for a slot when customizing.
|
|
291 :group - Name of a customization group this slot belongs in.
|
|
292 :printer - A function to call to print the value of a slot.
|
|
293 See `eieio-override-prin1' as an example.
|
|
294
|
|
295 A class can also have optional options. These options happen in place
|
|
296 of documentation, (including a :documentation tag) in addition to
|
|
297 documentation, or not at all. Supported options are:
|
|
298
|
|
299 :documentation - The doc-string used for this class.
|
|
300
|
|
301 Options added to EIEIO:
|
|
302
|
|
303 :allow-nil-initform - Non-nil to skip typechecking of initforms if nil.
|
|
304 :custom-groups - List of custom group names. Organizes slots into
|
|
305 reasonable groups for customizations.
|
|
306 :abstract - Non-nil to prevent instances of this class.
|
|
307 If a string, use as an error string if someone does
|
|
308 try to make an instance.
|
|
309 :method-invocation-order
|
|
310 - Control the method invokation order if there is
|
|
311 multiple inheritance. Valid values are:
|
|
312 :breadth-first - The default.
|
|
313 :depth-first
|
|
314
|
|
315 Options in CLOS not supported in EIEIO:
|
|
316
|
|
317 :metaclass - Class to use in place of `standard-class'
|
|
318 :default-initargs - Initargs to use when initializing new objects of
|
|
319 this class.
|
|
320
|
|
321 Due to the way class options are set up, you can add any tags in you
|
|
322 wish, and reference them using the function `class-option'."
|
|
323 ;; We must `eval-and-compile' this so that when we byte compile
|
|
324 ;; an eieio program, there is no need to load it ahead of time.
|
|
325 ;; It also provides lots of nice debugging errors at compile time.
|
|
326 `(eval-and-compile
|
|
327 (eieio-defclass ',name ',superclass ',slots ',options-and-doc)))
|
|
328
|
|
329 (defvar eieio-defclass-autoload-map (make-vector 7 nil)
|
|
330 "Symbol map of superclasses we find in autoloads.")
|
|
331
|
|
332 ;; We autoload this because it's used in `make-autoload'.
|
|
333 ;;;###autoload
|
|
334 (defun eieio-defclass-autoload (cname superclasses filename doc)
|
|
335 "Create autoload symbols for the EIEIO class CNAME.
|
|
336 SUPERCLASSES are the superclasses that CNAME inherites from.
|
|
337 DOC is the docstring for CNAME.
|
|
338 This function creates a mock-class for CNAME and adds it into
|
|
339 SUPERCLASSES as children.
|
|
340 It creates an autoload function for CNAME's constructor."
|
|
341 ;; Assume we've already debugged inputs.
|
|
342
|
|
343 (let* ((oldc (when (class-p cname) (class-v cname)))
|
|
344 (newc (make-vector class-num-slots nil))
|
|
345 )
|
|
346 (if oldc
|
|
347 nil ;; Do nothing if we already have this class.
|
|
348
|
|
349 ;; Create the class in NEWC, but don't fill anything else in.
|
|
350 (aset newc 0 'defclass)
|
|
351 (aset newc class-symbol cname)
|
|
352
|
|
353 (let ((clear-parent nil))
|
|
354 ;; No parents?
|
|
355 (when (not superclasses)
|
|
356 (setq superclasses '(eieio-default-superclass)
|
|
357 clear-parent t)
|
|
358 )
|
|
359
|
|
360 ;; Hook our new class into the existing structures so we can
|
|
361 ;; autoload it later.
|
|
362 (dolist (SC superclasses)
|
|
363
|
|
364
|
|
365 ;; TODO - If we create an autoload that is in the map, that
|
|
366 ;; map needs to be cleared!
|
|
367
|
|
368
|
|
369 ;; Does our parent exist?
|
|
370 (if (not (class-p SC))
|
|
371
|
|
372 ;; Create a symbol for this parent, and then store this
|
|
373 ;; parent on that symbol.
|
|
374 (let ((sym (intern (symbol-name SC) eieio-defclass-autoload-map)))
|
|
375 (if (not (boundp sym))
|
|
376 (set sym (list cname))
|
|
377 (add-to-list sym cname))
|
|
378 )
|
|
379
|
|
380 ;; We have a parent, save the child in there.
|
|
381 (when (not (member cname (aref (class-v SC) class-children)))
|
|
382 (aset (class-v SC) class-children
|
|
383 (cons cname (aref (class-v SC) class-children)))))
|
|
384
|
|
385 ;; save parent in child
|
|
386 (aset newc class-parent (cons SC (aref newc class-parent)))
|
|
387 )
|
|
388
|
|
389 ;; turn this into a useable self-pointing symbol
|
|
390 (set cname cname)
|
|
391
|
|
392 ;; Store the new class vector definition into the symbol. We need to
|
|
393 ;; do this first so that we can call defmethod for the accessor.
|
|
394 ;; The vector will be updated by the following while loop and will not
|
|
395 ;; need to be stored a second time.
|
|
396 (put cname 'eieio-class-definition newc)
|
|
397
|
|
398 ;; Clear the parent
|
|
399 (if clear-parent (aset newc class-parent nil))
|
|
400
|
|
401 ;; Create an autoload on top of our constructor function.
|
|
402 (autoload cname filename doc nil nil)
|
|
403 (autoload (intern (concat (symbol-name cname) "-p")) filename "" nil nil)
|
|
404 (autoload (intern (concat (symbol-name cname) "-child-p")) filename "" nil nil)
|
|
405
|
|
406 ))))
|
|
407
|
|
408 (defsubst eieio-class-un-autoload (cname)
|
|
409 "If class CNAME is in an autoload state, load it's file."
|
|
410 (when (eq (car-safe (symbol-function cname)) 'autoload)
|
|
411 (load-library (car (cdr (symbol-function cname))))))
|
|
412
|
|
413 (defun eieio-defclass (cname superclasses slots options-and-doc)
|
|
414 "See `defclass' for more information.
|
|
415 Define CNAME as a new subclass of SUPERCLASSES, with SLOTS being the
|
|
416 slots residing in that class definition, and with options or documentation
|
|
417 OPTIONS-AND-DOC as the toplevel documentation for this class."
|
|
418 ;; Run our eieio-hook each time, and clear it when we are done.
|
|
419 ;; This way people can add hooks safely if they want to modify eieio
|
|
420 ;; or add definitions when eieio is loaded or something like that.
|
|
421 (run-hooks 'eieio-hook)
|
|
422 (setq eieio-hook nil)
|
|
423
|
|
424 (if (not (symbolp cname)) (signal 'wrong-type-argument '(symbolp cname)))
|
|
425 (if (not (listp superclasses)) (signal 'wrong-type-argument '(listp superclasses)))
|
|
426
|
|
427 (let* ((pname (if superclasses superclasses nil))
|
|
428 (newc (make-vector class-num-slots nil))
|
|
429 (oldc (when (class-p cname) (class-v cname)))
|
|
430 (groups nil) ;; list of groups id'd from slots
|
|
431 (options nil)
|
|
432 (clearparent nil))
|
|
433
|
|
434 (aset newc 0 'defclass)
|
|
435 (aset newc class-symbol cname)
|
|
436
|
|
437 ;; If this class already existed, and we are updating it's structure,
|
|
438 ;; make sure we keep the old child list. This can cause bugs, but
|
|
439 ;; if no new slots are created, it also saves time, and prevents
|
|
440 ;; method table breakage, particularly when the users is only
|
|
441 ;; byte compiling an EIEIO file.
|
|
442 (if oldc
|
|
443 (aset newc class-children (aref oldc class-children))
|
|
444 ;; If the old class did not exist, but did exist in the autoload map, then adopt those children.
|
|
445 ;; This is like the above, but deals with autoloads nicely.
|
|
446 (let ((sym (intern-soft (symbol-name cname) eieio-defclass-autoload-map)))
|
|
447 (when sym
|
|
448 (condition-case nil
|
|
449 (aset newc class-children (symbol-value sym))
|
|
450 (error nil))
|
|
451 (unintern (symbol-name cname) eieio-defclass-autoload-map)
|
|
452 ))
|
|
453 )
|
|
454
|
|
455 (cond ((and (stringp (car options-and-doc))
|
|
456 (/= 1 (% (length options-and-doc) 2)))
|
|
457 (error "Too many arguments to `defclass'"))
|
|
458 ((and (symbolp (car options-and-doc))
|
|
459 (/= 0 (% (length options-and-doc) 2)))
|
|
460 (error "Too many arguments to `defclass'"))
|
|
461 )
|
|
462
|
|
463 (setq options
|
|
464 (if (stringp (car options-and-doc))
|
|
465 (cons :documentation options-and-doc)
|
|
466 options-and-doc))
|
|
467
|
|
468 (if pname
|
|
469 (progn
|
|
470 (while pname
|
|
471 (if (and (car pname) (symbolp (car pname)))
|
|
472 (if (not (class-p (car pname)))
|
|
473 ;; bad class
|
|
474 (error "Given parent class %s is not a class" (car pname))
|
|
475 ;; good parent class...
|
|
476 ;; save new child in parent
|
|
477 (when (not (member cname (aref (class-v (car pname)) class-children)))
|
|
478 (aset (class-v (car pname)) class-children
|
|
479 (cons cname (aref (class-v (car pname)) class-children))))
|
|
480 ;; Get custom groups, and store them into our local copy.
|
|
481 (mapc (lambda (g) (add-to-list 'groups g))
|
|
482 (class-option (car pname) :custom-groups))
|
|
483 ;; save parent in child
|
|
484 (aset newc class-parent (cons (car pname) (aref newc class-parent))))
|
|
485 (error "Invalid parent class %s" pname))
|
|
486 (setq pname (cdr pname)))
|
|
487 ;; Reverse the list of our parents so that they are prioritized in
|
|
488 ;; the same order as specified in the code.
|
|
489 (aset newc class-parent (nreverse (aref newc class-parent))) )
|
|
490 ;; If there is nothing to loop over, then inherit from the
|
|
491 ;; default superclass.
|
|
492 (unless (eq cname 'eieio-default-superclass)
|
|
493 ;; adopt the default parent here, but clear it later...
|
|
494 (setq clearparent t)
|
|
495 ;; save new child in parent
|
|
496 (if (not (member cname (aref (class-v 'eieio-default-superclass) class-children)))
|
|
497 (aset (class-v 'eieio-default-superclass) class-children
|
|
498 (cons cname (aref (class-v 'eieio-default-superclass) class-children))))
|
|
499 ;; save parent in child
|
|
500 (aset newc class-parent (list eieio-default-superclass))))
|
|
501
|
|
502 ;; turn this into a useable self-pointing symbol
|
|
503 (set cname cname)
|
|
504
|
|
505 ;; These two tests must be created right away so we can have self-
|
|
506 ;; referencing classes. ei, a class whose slot can contain only
|
|
507 ;; pointers to itself.
|
|
508
|
|
509 ;; Create the test function
|
|
510 (let ((csym (intern (concat (symbol-name cname) "-p"))))
|
|
511 (fset csym
|
|
512 (list 'lambda (list 'obj)
|
|
513 (format "Test OBJ to see if it an object of type %s" cname)
|
|
514 (list 'and '(eieio-object-p obj)
|
|
515 (list 'same-class-p 'obj cname)))))
|
|
516
|
|
517 ;; Make sure the method invocation order is a valid value.
|
|
518 (let ((io (class-option-assoc options :method-invocation-order)))
|
|
519 (when (and io (not (member io '(:depth-first :breadth-first))))
|
|
520 (error "Method invocation order %s is not allowed" io)
|
|
521 ))
|
|
522
|
|
523 ;; Create a handy child test too
|
|
524 (let ((csym (intern (concat (symbol-name cname) "-child-p"))))
|
|
525 (fset csym
|
|
526 `(lambda (obj)
|
|
527 ,(format
|
|
528 "Test OBJ to see if it an object is a child of type %s"
|
|
529 cname)
|
|
530 (and (eieio-object-p obj)
|
|
531 (object-of-class-p obj ,cname))))
|
|
532
|
|
533 ;; When using typep, (typep OBJ 'myclass) returns t for objects which
|
|
534 ;; are subclasses of myclass. For our predicates, however, it is
|
|
535 ;; important for EIEIO to be backwards compatible, where
|
|
536 ;; myobject-p, and myobject-child-p are different.
|
|
537 ;; "cl" uses this technique to specify symbols with specific typep
|
|
538 ;; test, so we can let typep have the CLOS documented behavior
|
|
539 ;; while keeping our above predicate clean.
|
|
540 (eval `(deftype ,cname ()
|
|
541 '(satisfies
|
|
542 ,(intern (concat (symbol-name cname) "-child-p")))))
|
|
543
|
|
544 )
|
|
545
|
|
546 ;; before adding new slots, lets add all the methods and classes
|
|
547 ;; in from the parent class
|
|
548 (eieio-copy-parents-into-subclass newc superclasses)
|
|
549
|
|
550 ;; Store the new class vector definition into the symbol. We need to
|
|
551 ;; do this first so that we can call defmethod for the accessor.
|
|
552 ;; The vector will be updated by the following while loop and will not
|
|
553 ;; need to be stored a second time.
|
|
554 (put cname 'eieio-class-definition newc)
|
|
555
|
|
556 ;; Query each slot in the declaration list and mangle into the
|
|
557 ;; class structure I have defined.
|
|
558 (while slots
|
|
559 (let* ((slot1 (car slots))
|
|
560 (name (car slot1))
|
|
561 (slot (cdr slot1))
|
|
562 (acces (plist-get slot ':accessor))
|
|
563 (init (or (plist-get slot ':initform)
|
|
564 (if (member ':initform slot) nil
|
|
565 eieio-unbound)))
|
|
566 (initarg (plist-get slot ':initarg))
|
|
567 (docstr (plist-get slot ':documentation))
|
|
568 (prot (plist-get slot ':protection))
|
|
569 (reader (plist-get slot ':reader))
|
|
570 (writer (plist-get slot ':writer))
|
|
571 (alloc (plist-get slot ':allocation))
|
|
572 (type (plist-get slot ':type))
|
|
573 (custom (plist-get slot ':custom))
|
|
574 (label (plist-get slot ':label))
|
|
575 (customg (plist-get slot ':group))
|
|
576 (printer (plist-get slot ':printer))
|
|
577
|
|
578 (skip-nil (class-option-assoc options :allow-nil-initform))
|
|
579 )
|
|
580
|
|
581 (if eieio-error-unsupported-class-tags
|
|
582 (let ((tmp slot))
|
|
583 (while tmp
|
|
584 (if (not (member (car tmp) '(:accessor
|
|
585 :initform
|
|
586 :initarg
|
|
587 :documentation
|
|
588 :protection
|
|
589 :reader
|
|
590 :writer
|
|
591 :allocation
|
|
592 :type
|
|
593 :custom
|
|
594 :label
|
|
595 :group
|
|
596 :printer
|
|
597 :allow-nil-initform
|
|
598 :custom-groups)))
|
|
599 (signal 'invalid-slot-type (list (car tmp))))
|
|
600 (setq tmp (cdr (cdr tmp))))))
|
|
601
|
|
602 ;; Clean up the meaning of protection.
|
|
603 (cond ((or (eq prot 'public) (eq prot :public)) (setq prot nil))
|
|
604 ((or (eq prot 'protected) (eq prot :protected)) (setq prot 'protected))
|
|
605 ((or (eq prot 'private) (eq prot :private)) (setq prot 'private))
|
|
606 ((eq prot nil) nil)
|
|
607 (t (signal 'invalid-slot-type (list ':protection prot))))
|
|
608
|
|
609 ;; Make sure the :allocation parameter has a valid value.
|
|
610 (if (not (or (not alloc) (eq alloc :class) (eq alloc :instance)))
|
|
611 (signal 'invalid-slot-type (list ':allocation alloc)))
|
|
612
|
|
613 ;; The default type specifier is supposed to be t, meaning anything.
|
|
614 (if (not type) (setq type t))
|
|
615
|
|
616 ;; Label is nil, or a string
|
|
617 (if (not (or (null label) (stringp label)))
|
|
618 (signal 'invalid-slot-type (list ':label label)))
|
|
619
|
|
620 ;; Is there an initarg, but allocation of class?
|
|
621 (if (and initarg (eq alloc :class))
|
|
622 (message "Class allocated slots do not need :initarg"))
|
|
623
|
|
624 ;; intern the symbol so we can use it blankly
|
|
625 (if initarg (set initarg initarg))
|
|
626
|
|
627 ;; The customgroup should be a list of symbols
|
|
628 (cond ((null customg)
|
|
629 (setq customg '(default)))
|
|
630 ((not (listp customg))
|
|
631 (setq customg (list customg))))
|
|
632 ;; The customgroup better be a symbol, or list of symbols.
|
|
633 (mapc (lambda (cg)
|
|
634 (if (not (symbolp cg))
|
|
635 (signal 'invalid-slot-type (list ':group cg))))
|
|
636 customg)
|
|
637
|
|
638 ;; First up, add this slot into our new class.
|
|
639 (eieio-add-new-slot newc name init docstr type custom label customg printer
|
|
640 prot initarg alloc 'defaultoverride skip-nil)
|
|
641
|
|
642 ;; We need to id the group, and store them in a group list attribute.
|
|
643 (mapc (lambda (cg) (add-to-list 'groups cg)) customg)
|
|
644
|
|
645 ;; anyone can have an accessor function. This creates a function
|
|
646 ;; of the specified name, and also performs a `defsetf' if applicable
|
|
647 ;; so that users can `setf' the space returned by this function
|
|
648 (if acces
|
|
649 (progn
|
|
650 (eieio-defmethod acces
|
|
651 (list (if (eq alloc :class) :static :primary)
|
|
652 (list (list 'this cname))
|
|
653 (format
|
|
654 "Retrieves the slot `%s' from an object of class `%s'"
|
|
655 name cname)
|
|
656 (list 'if (list 'slot-boundp 'this (list 'quote name))
|
|
657 (list 'eieio-oref 'this (list 'quote name))
|
|
658 ;; Else - Some error? nil?
|
|
659 nil
|
|
660 )))
|
|
661 ;; Thanks Pascal Bourguignon <pjb@informatimago.com>
|
|
662 ;; For this complex macro.
|
|
663 (eval (macroexpand
|
|
664 (list 'defsetf acces '(widget) '(store)
|
|
665 (list 'list ''eieio-oset 'widget
|
|
666 (list 'quote (list 'quote name)) 'store))))
|
|
667 ;;`(defsetf ,acces (widget) (store) (eieio-oset widget ',cname store))
|
|
668 )
|
|
669 )
|
|
670 ;; If a writer is defined, then create a generic method of that
|
|
671 ;; name whose purpose is to set the value of the slot.
|
|
672 (if writer
|
|
673 (progn
|
|
674 (eieio-defmethod writer
|
|
675 (list (list (list 'this cname) 'value)
|
|
676 (format "Set the slot `%s' of an object of class `%s'"
|
|
677 name cname)
|
|
678 `(setf (slot-value this ',name) value)))
|
|
679 ))
|
|
680 ;; If a reader is defined, then create a generic method
|
|
681 ;; of that name whose purpose is to access this slot value.
|
|
682 (if reader
|
|
683 (progn
|
|
684 (eieio-defmethod reader
|
|
685 (list (list (list 'this cname))
|
|
686 (format "Access the slot `%s' from object of class `%s'"
|
|
687 name cname)
|
|
688 `(slot-value this ',name)))))
|
|
689 )
|
|
690 (setq slots (cdr slots)))
|
|
691
|
|
692 ;; Now that everything has been loaded up, all our lists are backwards! Fix that up now.
|
|
693 (aset newc class-public-a (nreverse (aref newc class-public-a)))
|
|
694 (aset newc class-public-d (nreverse (aref newc class-public-d)))
|
|
695 (aset newc class-public-doc (nreverse (aref newc class-public-doc)))
|
|
696 (aset newc class-public-type
|
|
697 (apply 'vector (nreverse (aref newc class-public-type))))
|
|
698 (aset newc class-public-custom (nreverse (aref newc class-public-custom)))
|
|
699 (aset newc class-public-custom-label (nreverse (aref newc class-public-custom-label)))
|
|
700 (aset newc class-public-custom-group (nreverse (aref newc class-public-custom-group)))
|
|
701 (aset newc class-public-printer (nreverse (aref newc class-public-printer)))
|
|
702 (aset newc class-protection (nreverse (aref newc class-protection)))
|
|
703 (aset newc class-initarg-tuples (nreverse (aref newc class-initarg-tuples)))
|
|
704
|
|
705 ;; The storage for class-class-allocation-type needs to be turned into
|
|
706 ;; a vector now.
|
|
707 (aset newc class-class-allocation-type
|
|
708 (apply 'vector (aref newc class-class-allocation-type)))
|
|
709
|
|
710 ;; Also, take class allocated values, and vectorize them for speed.
|
|
711 (aset newc class-class-allocation-values
|
|
712 (apply 'vector (aref newc class-class-allocation-values)))
|
|
713
|
|
714 ;; Attach slot symbols into an obarray, and store the index of
|
|
715 ;; this slot as the variable slot in this new symbol. We need to
|
|
716 ;; know about primes, because obarrays are best set in vectors of
|
|
717 ;; prime number length, and we also need to make our vector small
|
|
718 ;; to save space, and also optimal for the number of items we have.
|
|
719 (let* ((cnt 0)
|
|
720 (pubsyms (aref newc class-public-a))
|
|
721 (prots (aref newc class-protection))
|
|
722 (l (length pubsyms))
|
|
723 (vl (let ((primes '( 3 5 7 11 13 17 19 23 29 31 37 41 43 47
|
|
724 53 59 61 67 71 73 79 83 89 97 101 )))
|
|
725 (while (and primes (< (car primes) l))
|
|
726 (setq primes (cdr primes)))
|
|
727 (car primes)))
|
|
728 (oa (make-vector vl 0))
|
|
729 (newsym))
|
|
730 (while pubsyms
|
|
731 (setq newsym (intern (symbol-name (car pubsyms)) oa))
|
|
732 (set newsym cnt)
|
|
733 (setq cnt (1+ cnt))
|
|
734 (if (car prots) (put newsym 'protection (car prots)))
|
|
735 (setq pubsyms (cdr pubsyms)
|
|
736 prots (cdr prots)))
|
|
737 (aset newc class-symbol-obarray oa)
|
|
738 )
|
|
739
|
|
740 ;; Create the constructor function
|
|
741 (if (class-option-assoc options :abstract)
|
|
742 ;; Abstract classes cannot be instantiated. Say so.
|
|
743 (let ((abs (class-option-assoc options :abstract)))
|
|
744 (if (not (stringp abs))
|
|
745 (setq abs (format "Class %s is abstract" cname)))
|
|
746 (fset cname
|
|
747 `(lambda (&rest stuff)
|
|
748 ,(format "You cannot create a new object of type %s" cname)
|
|
749 (error ,abs))))
|
|
750
|
|
751 ;; Non-abstract classes need a constructor.
|
|
752 (fset cname
|
|
753 `(lambda (newname &rest slots)
|
|
754 ,(format "Create a new object with name NAME of class type %s" cname)
|
|
755 (apply 'constructor ,cname newname slots)))
|
|
756 )
|
|
757
|
|
758 ;; Set up a specialized doc string.
|
|
759 ;; Use stored value since it is calculated in a non-trivial way
|
|
760 (put cname 'variable-documentation
|
|
761 (class-option-assoc options :documentation))
|
|
762
|
|
763 ;; We have a list of custom groups. Store them into the options.
|
|
764 (let ((g (class-option-assoc options :custom-groups)))
|
|
765 (mapc (lambda (cg) (add-to-list 'g cg)) groups)
|
|
766 (if (memq :custom-groups options)
|
|
767 (setcar (cdr (memq :custom-groups options)) g)
|
|
768 (setq options (cons :custom-groups (cons g options)))))
|
|
769
|
|
770 ;; Set up the options we have collected.
|
|
771 (aset newc class-options options)
|
|
772
|
|
773 ;; if this is a superclass, clear out parent (which was set to the
|
|
774 ;; default superclass eieio-default-superclass)
|
|
775 (if clearparent (aset newc class-parent nil))
|
|
776
|
|
777 ;; Create the cached default object.
|
|
778 (let ((cache (make-vector (+ (length (aref newc class-public-a))
|
|
779 3) nil)))
|
|
780 (aset cache 0 'object)
|
|
781 (aset cache object-class cname)
|
|
782 (aset cache object-name 'default-cache-object)
|
|
783 (let ((eieio-skip-typecheck t))
|
|
784 ;; All type-checking has been done to our satisfaction
|
|
785 ;; before this call. Don't waste our time in this call..
|
|
786 (eieio-set-defaults cache t))
|
|
787 (aset newc class-default-object-cache cache))
|
|
788
|
|
789 ;; Return our new class object
|
|
790 ;; newc
|
|
791 cname
|
|
792 ))
|
|
793
|
|
794 (defun eieio-perform-slot-validation-for-default (slot spec value skipnil)
|
|
795 "For SLOT, signal if SPEC does not match VALUE.
|
|
796 If SKIPNIL is non-nil, then if VALUE is nil, return t."
|
|
797 (let ((val (eieio-default-eval-maybe value)))
|
|
798 (if (and (not eieio-skip-typecheck)
|
|
799 (not (and skipnil (null val)))
|
|
800 (not (eieio-perform-slot-validation spec val)))
|
|
801 (signal 'invalid-slot-type (list slot spec val)))))
|
|
802
|
|
803 (defun eieio-add-new-slot (newc a d doc type cust label custg print prot init alloc
|
|
804 &optional defaultoverride skipnil)
|
|
805 "Add into NEWC attribute A.
|
|
806 If A already exists in NEWC, then do nothing. If it doesn't exist,
|
|
807 then also add in D (defualt), DOC, TYPE, CUST, LABEL, CUSTG, PRINT, PROT, and INIT arg.
|
|
808 Argument ALLOC specifies if the slot is allocated per instance, or per class.
|
|
809 If optional DEFAULTOVERRIDE is non-nil, then if A exists in NEWC,
|
|
810 we must override it's value for a default.
|
|
811 Optional argument SKIPNIL indicates if type checking should be skipped
|
|
812 if default value is nil."
|
|
813 ;; Make sure we duplicate those items that are sequences.
|
|
814 (condition-case nil
|
|
815 (if (sequencep d) (setq d (copy-sequence d)))
|
|
816 ;; This copy can fail on a cons cell with a non-cons in the cdr. Lets skip it if it doesn't work.
|
|
817 (error nil))
|
|
818 (if (sequencep type) (setq type (copy-sequence type)))
|
|
819 (if (sequencep cust) (setq cust (copy-sequence cust)))
|
|
820 (if (sequencep custg) (setq custg (copy-sequence custg)))
|
|
821
|
|
822 ;; To prevent override information w/out specification of storage,
|
|
823 ;; we need to do this little hack.
|
|
824 (if (member a (aref newc class-class-allocation-a)) (setq alloc ':class))
|
|
825
|
|
826 (if (or (not alloc) (and (symbolp alloc) (eq alloc ':instance)))
|
|
827 ;; In this case, we modify the INSTANCE version of a given slot.
|
|
828
|
|
829 (progn
|
|
830
|
|
831 ;; Only add this element if it is so-far unique
|
|
832 (if (not (member a (aref newc class-public-a)))
|
|
833 (progn
|
|
834 (eieio-perform-slot-validation-for-default a type d skipnil)
|
|
835 (aset newc class-public-a (cons a (aref newc class-public-a)))
|
|
836 (aset newc class-public-d (cons d (aref newc class-public-d)))
|
|
837 (aset newc class-public-doc (cons doc (aref newc class-public-doc)))
|
|
838 (aset newc class-public-type (cons type (aref newc class-public-type)))
|
|
839 (aset newc class-public-custom (cons cust (aref newc class-public-custom)))
|
|
840 (aset newc class-public-custom-label (cons label (aref newc class-public-custom-label)))
|
|
841 (aset newc class-public-custom-group (cons custg (aref newc class-public-custom-group)))
|
|
842 (aset newc class-public-printer (cons print (aref newc class-public-printer)))
|
|
843 (aset newc class-protection (cons prot (aref newc class-protection)))
|
|
844 (aset newc class-initarg-tuples (cons (cons init a) (aref newc class-initarg-tuples)))
|
|
845 )
|
|
846 ;; When defaultoverride is true, we are usually adding new local
|
|
847 ;; attributes which must override the default value of any slot
|
|
848 ;; passed in by one of the parent classes.
|
|
849 (when defaultoverride
|
|
850 ;; There is a match, and we must override the old value.
|
|
851 (let* ((ca (aref newc class-public-a))
|
|
852 (np (member a ca))
|
|
853 (num (- (length ca) (length np)))
|
|
854 (dp (if np (nthcdr num (aref newc class-public-d))
|
|
855 nil))
|
|
856 (tp (if np (nth num (aref newc class-public-type))))
|
|
857 )
|
|
858 (if (not np)
|
|
859 (error "Eieio internal error overriding default value for %s"
|
|
860 a)
|
|
861 ;; If type is passed in, is it the same?
|
|
862 (if (not (eq type t))
|
|
863 (if (not (equal type tp))
|
|
864 (error
|
|
865 "Child slot type `%s' does not match inherited type `%s' for `%s'"
|
|
866 type tp a)))
|
|
867 ;; If we have a repeat, only update the initarg...
|
|
868 (unless (eq d eieio-unbound)
|
|
869 (eieio-perform-slot-validation-for-default a tp d skipnil)
|
|
870 (setcar dp d))
|
|
871 ;; If we have a new initarg, check for it.
|
|
872 (when init
|
|
873 (let* ((inits (aref newc class-initarg-tuples))
|
|
874 (inita (rassq a inits)))
|
|
875 ;; Replace the CAR of the associate INITA.
|
|
876 ;;(message "Initarg: %S replace %s" inita init)
|
|
877 (setcar inita init)
|
|
878 ))
|
|
879
|
|
880 ;; PLN Tue Jun 26 11:57:06 2007 : The protection is
|
|
881 ;; checked and SHOULD match the superclass
|
|
882 ;; protection. Otherwise an error is thrown. However
|
|
883 ;; I wonder if a more flexible schedule might be
|
|
884 ;; implemented.
|
|
885 ;;
|
|
886 ;; EML - We used to have (if prot... here,
|
|
887 ;; but a prot of 'nil means public.
|
|
888 ;;
|
|
889 (let ((super-prot (nth num (aref newc class-protection)))
|
|
890 )
|
|
891 (if (not (eq prot super-prot))
|
|
892 (error "Child slot protection `%s' does not match inherited protection `%s' for `%s'"
|
|
893 prot super-prot a)))
|
|
894 ;; End original PLN
|
|
895
|
|
896 ;; PLN Tue Jun 26 11:57:06 2007 :
|
|
897 ;; We do a non redundant combination of ancient
|
|
898 ;; custom groups and new ones using the common lisp
|
|
899 ;; `union' method.
|
|
900 (when custg
|
|
901 (let ((where-groups
|
|
902 (nthcdr num (aref newc class-public-custom-group))))
|
|
903 (setcar where-groups
|
|
904 (union (car where-groups)
|
|
905 (if (listp custg) custg (list custg))))))
|
|
906 ;; End PLN
|
|
907
|
|
908 ;; PLN Mon Jun 25 22:44:34 2007 : If a new cust is
|
|
909 ;; set, simply replaces the old one.
|
|
910 (when cust
|
|
911 ;; (message "Custom type redefined to %s" cust)
|
|
912 (setcar (nthcdr num (aref newc class-public-custom)) cust))
|
|
913
|
|
914 ;; If a new label is specified, it simply replaces
|
|
915 ;; the old one.
|
|
916 (when label
|
|
917 ;; (message "Custom label redefined to %s" label)
|
|
918 (setcar (nthcdr num (aref newc class-public-custom-label)) label))
|
|
919 ;; End PLN
|
|
920
|
|
921 ;; PLN Sat Jun 30 17:24:42 2007 : when a new
|
|
922 ;; doc is specified, simply replaces the old one.
|
|
923 (when doc
|
|
924 ;;(message "Documentation redefined to %s" doc)
|
|
925 (setcar (nthcdr num (aref newc class-public-doc))
|
|
926 doc))
|
|
927 ;; End PLN
|
|
928
|
|
929 ;; If a new printer is specified, it simply replaces
|
|
930 ;; the old one.
|
|
931 (when print
|
|
932 ;; (message "printer redefined to %s" print)
|
|
933 (setcar (nthcdr num (aref newc class-public-printer)) print))
|
|
934
|
|
935 )))
|
|
936 ))
|
|
937
|
|
938 ;; CLASS ALLOCATED SLOTS
|
|
939 (let ((value (eieio-default-eval-maybe d)))
|
|
940 (if (not (member a (aref newc class-class-allocation-a)))
|
|
941 (progn
|
|
942 (eieio-perform-slot-validation-for-default a type value skipnil)
|
|
943 ;; Here we have found a :class version of a slot. This
|
|
944 ;; requires a very different aproach.
|
|
945 (aset newc class-class-allocation-a (cons a (aref newc class-class-allocation-a)))
|
|
946 (aset newc class-class-allocation-doc (cons doc (aref newc class-class-allocation-doc)))
|
|
947 (aset newc class-class-allocation-type (cons type (aref newc class-class-allocation-type)))
|
|
948 (aset newc class-class-allocation-custom (cons cust (aref newc class-class-allocation-custom)))
|
|
949 (aset newc class-class-allocation-custom-label (cons label (aref newc class-class-allocation-custom-label)))
|
|
950 (aset newc class-class-allocation-custom-group (cons custg (aref newc class-class-allocation-custom-group)))
|
|
951 (aset newc class-class-allocation-protection (cons prot (aref newc class-class-allocation-protection)))
|
|
952 ;; Default value is stored in the 'values section, since new objects
|
|
953 ;; can't initialize from this element.
|
|
954 (aset newc class-class-allocation-values (cons value (aref newc class-class-allocation-values))))
|
|
955 (when defaultoverride
|
|
956 ;; There is a match, and we must override the old value.
|
|
957 (let* ((ca (aref newc class-class-allocation-a))
|
|
958 (np (member a ca))
|
|
959 (num (- (length ca) (length np)))
|
|
960 (dp (if np
|
|
961 (nthcdr num
|
|
962 (aref newc class-class-allocation-values))
|
|
963 nil))
|
|
964 (tp (if np (nth num (aref newc class-class-allocation-type))
|
|
965 nil)))
|
|
966 (if (not np)
|
|
967 (error "Eieio internal error overriding default value for %s"
|
|
968 a)
|
|
969 ;; If type is passed in, is it the same?
|
|
970 (if (not (eq type t))
|
|
971 (if (not (equal type tp))
|
|
972 (error
|
|
973 "Child slot type `%s' does not match inherited type `%s' for `%s'"
|
|
974 type tp a)))
|
|
975 ;; EML - Note: the only reason to override a class bound slot
|
|
976 ;; is to change the default, so allow unbound in.
|
|
977
|
|
978 ;; If we have a repeat, only update the vlaue...
|
|
979 (eieio-perform-slot-validation-for-default a tp value skipnil)
|
|
980 (setcar dp value))
|
|
981
|
|
982 ;; PLN Tue Jun 26 11:57:06 2007 : The protection is
|
|
983 ;; checked and SHOULD match the superclass
|
|
984 ;; protection. Otherwise an error is thrown. However
|
|
985 ;; I wonder if a more flexible schedule might be
|
|
986 ;; implemented.
|
|
987 (let ((super-prot
|
|
988 (car (nthcdr num (aref newc class-class-allocation-protection)))))
|
|
989 (if (not (eq prot super-prot))
|
|
990 (error "Child slot protection `%s' does not match inherited protection `%s' for `%s'"
|
|
991 prot super-prot a)))
|
|
992 ;; We do a non redundant combination of ancient
|
|
993 ;; custom groups and new ones using the common lisp
|
|
994 ;; `union' method.
|
|
995 (when custg
|
|
996 (let ((where-groups
|
|
997 (nthcdr num (aref newc class-class-allocation-custom-group))))
|
|
998 (setcar where-groups
|
|
999 (union (car where-groups)
|
|
1000 (if (listp custg) custg (list custg))))))
|
|
1001 ;; End PLN
|
|
1002
|
|
1003 ;; PLN Sat Jun 30 17:24:42 2007 : when a new
|
|
1004 ;; doc is specified, simply replaces the old one.
|
|
1005 (when doc
|
|
1006 ;;(message "Documentation redefined to %s" doc)
|
|
1007 (setcar (nthcdr num (aref newc class-class-allocation-doc))
|
|
1008 doc))
|
|
1009 ;; End PLN
|
|
1010
|
|
1011 ;; If a new printer is specified, it simply replaces
|
|
1012 ;; the old one.
|
|
1013 (when print
|
|
1014 ;; (message "printer redefined to %s" print)
|
|
1015 (setcar (nthcdr num (aref newc class-class-allocation-printer)) print))
|
|
1016
|
|
1017 ))
|
|
1018 ))
|
|
1019 ))
|
|
1020
|
|
1021 (defun eieio-copy-parents-into-subclass (newc parents)
|
|
1022 "Copy into NEWC the slots of PARENTS.
|
|
1023 Follow the rules of not overwritting early parents when applying to
|
|
1024 the new child class."
|
|
1025 (let ((ps (aref newc class-parent))
|
|
1026 (sn (class-option-assoc (aref newc class-options)
|
|
1027 ':allow-nil-initform)))
|
|
1028 (while ps
|
|
1029 ;; First, duplicate all the slots of the parent.
|
|
1030 (let ((pcv (class-v (car ps))))
|
|
1031 (let ((pa (aref pcv class-public-a))
|
|
1032 (pd (aref pcv class-public-d))
|
|
1033 (pdoc (aref pcv class-public-doc))
|
|
1034 (ptype (aref pcv class-public-type))
|
|
1035 (pcust (aref pcv class-public-custom))
|
|
1036 (plabel (aref pcv class-public-custom-label))
|
|
1037 (pcustg (aref pcv class-public-custom-group))
|
|
1038 (printer (aref pcv class-public-printer))
|
|
1039 (pprot (aref pcv class-protection))
|
|
1040 (pinit (aref pcv class-initarg-tuples))
|
|
1041 (i 0))
|
|
1042 (while pa
|
|
1043 (eieio-add-new-slot newc
|
|
1044 (car pa) (car pd) (car pdoc) (aref ptype i)
|
|
1045 (car pcust) (car plabel) (car pcustg)
|
|
1046 (car printer)
|
|
1047 (car pprot) (car-safe (car pinit)) nil nil sn)
|
|
1048 ;; Increment each value.
|
|
1049 (setq pa (cdr pa)
|
|
1050 pd (cdr pd)
|
|
1051 pdoc (cdr pdoc)
|
|
1052 i (1+ i)
|
|
1053 pcust (cdr pcust)
|
|
1054 plabel (cdr plabel)
|
|
1055 pcustg (cdr pcustg)
|
|
1056 printer (cdr printer)
|
|
1057 pprot (cdr pprot)
|
|
1058 pinit (cdr pinit))
|
|
1059 )) ;; while/let
|
|
1060 ;; Now duplicate all the class alloc slots.
|
|
1061 (let ((pa (aref pcv class-class-allocation-a))
|
|
1062 (pdoc (aref pcv class-class-allocation-doc))
|
|
1063 (ptype (aref pcv class-class-allocation-type))
|
|
1064 (pcust (aref pcv class-class-allocation-custom))
|
|
1065 (plabel (aref pcv class-class-allocation-custom-label))
|
|
1066 (pcustg (aref pcv class-class-allocation-custom-group))
|
|
1067 (printer (aref pcv class-class-allocation-printer))
|
|
1068 (pprot (aref pcv class-class-allocation-protection))
|
|
1069 (pval (aref pcv class-class-allocation-values))
|
|
1070 (i 0))
|
|
1071 (while pa
|
|
1072 (eieio-add-new-slot newc
|
|
1073 (car pa) (aref pval i) (car pdoc) (aref ptype i)
|
|
1074 (car pcust) (car plabel) (car pcustg)
|
|
1075 (car printer)
|
|
1076 (car pprot) nil ':class sn)
|
|
1077 ;; Increment each value.
|
|
1078 (setq pa (cdr pa)
|
|
1079 pdoc (cdr pdoc)
|
|
1080 pcust (cdr pcust)
|
|
1081 plabel (cdr plabel)
|
|
1082 pcustg (cdr pcustg)
|
|
1083 printer (cdr printer)
|
|
1084 pprot (cdr pprot)
|
|
1085 i (1+ i))
|
|
1086 ))) ;; while/let
|
|
1087 ;; Loop over each parent class
|
|
1088 (setq ps (cdr ps)))
|
|
1089 ))
|
|
1090
|
|
1091 ;;; CLOS style implementation of object creators.
|
|
1092 ;;
|
|
1093 (defun make-instance (class &rest initargs)
|
|
1094 "Make a new instance of CLASS based on INITARGS.
|
|
1095 CLASS is a class symbol. For example:
|
|
1096
|
|
1097 (make-instance 'foo)
|
|
1098
|
|
1099 INITARGS is a property list with keywords based on the :initarg
|
|
1100 for each slot. For example:
|
|
1101
|
|
1102 (make-instance 'foo :slot1 value1 :slotN valueN)
|
|
1103
|
|
1104 Compatability note:
|
|
1105
|
|
1106 If the first element of INITARGS is a string, it is used as the
|
|
1107 name of the class.
|
|
1108
|
|
1109 In EIEIO, the class' constructor requires a name for use when printing.
|
|
1110 `make-instance' in CLOS doesn't use names the way Emacs does, so the
|
|
1111 class is used as the name slot instead when INITARGS doesn't start with
|
|
1112 a string."
|
|
1113 (if (and (car initargs) (stringp (car initargs)))
|
|
1114 (apply (class-constructor class) initargs)
|
|
1115 (apply (class-constructor class)
|
|
1116 (cond ((symbolp class) (symbol-name class))
|
|
1117 (t (format "%S" class)))
|
|
1118 initargs)))
|
|
1119
|
|
1120
|
|
1121 ;;; CLOS methods and generics
|
|
1122 ;;
|
|
1123 (defmacro defgeneric (method args &optional doc-string)
|
|
1124 "Create a generic function METHOD. ARGS is ignored.
|
|
1125 DOC-STRING is the base documentation for this class. A generic
|
|
1126 function has no body, as it's purpose is to decide which method body
|
|
1127 is appropriate to use. Use `defmethod' to create methods, and it
|
|
1128 calls defgeneric for you. With this implementation the arguments are
|
|
1129 currently ignored. You can use `defgeneric' to apply specialized
|
|
1130 top level documentation to a method."
|
|
1131 `(eieio-defgeneric (quote ,method) ,doc-string))
|
|
1132
|
|
1133 (defun eieio-defgeneric-form (method doc-string)
|
|
1134 "The lambda form that would be used as the function defined on METHOD.
|
|
1135 All methods should call the same EIEIO function for dispatch.
|
|
1136 DOC-STRING is the documentation attached to METHOD."
|
|
1137 `(lambda (&rest local-args)
|
|
1138 ,doc-string
|
|
1139 (eieio-generic-call (quote ,method) local-args)))
|
|
1140
|
|
1141 (defsubst eieio-defgeneric-reset-generic-form (method)
|
|
1142 "Setup METHOD to call the generic form."
|
|
1143 (let ((doc-string (documentation method)))
|
|
1144 (fset method (eieio-defgeneric-form method doc-string))))
|
|
1145
|
|
1146 (defun eieio-defgeneric-form-primary-only (method doc-string)
|
|
1147 "The lambda form that would be used as the function defined on METHOD.
|
|
1148 All methods should call the same EIEIO function for dispatch.
|
|
1149 DOC-STRING is the documentation attached to METHOD."
|
|
1150 `(lambda (&rest local-args)
|
|
1151 ,doc-string
|
|
1152 (eieio-generic-call-primary-only (quote ,method) local-args)))
|
|
1153
|
|
1154 (defsubst eieio-defgeneric-reset-generic-form-primary-only (method)
|
|
1155 "Setup METHOD to call the generic form."
|
|
1156 (let ((doc-string (documentation method)))
|
|
1157 (fset method (eieio-defgeneric-form-primary-only method doc-string))))
|
|
1158
|
|
1159 (defun eieio-defgeneric-form-primary-only-one (method doc-string
|
|
1160 class
|
|
1161 impl
|
|
1162 )
|
|
1163 "The lambda form that would be used as the function defined on METHOD.
|
|
1164 All methods should call the same EIEIO function for dispatch.
|
|
1165 DOC-STRING is the documentation attached to METHOD.
|
|
1166 CLASS is the class symbol needed for private method access.
|
|
1167 IMPL is the symbol holding the method implementation."
|
|
1168 ;; NOTE: I tried out byte compiling this little fcn. Turns out it
|
|
1169 ;; is faster to execute this for not byte-compiled. ie, install this,
|
|
1170 ;; then measure calls going through here. I wonder why.
|
|
1171 (require 'bytecomp)
|
|
1172 (let ((byte-compile-free-references nil)
|
|
1173 (byte-compile-warnings nil)
|
|
1174 )
|
|
1175 (byte-compile-lambda
|
|
1176 `(lambda (&rest local-args)
|
|
1177 ,doc-string
|
|
1178 ;; This is a cool cheat. Usually we need to look up in the
|
|
1179 ;; method table to find out if there is a method or not. We can
|
|
1180 ;; instead make that determination at load time when there is
|
|
1181 ;; only one method. If the first arg is not a child of the class
|
|
1182 ;; of that one implementation, then clearly, there is no method def.
|
|
1183 (if (not (eieio-object-p (car local-args)))
|
|
1184 ;; Not an object. Just signal.
|
|
1185 (signal 'no-method-definition (list ,(list 'quote method) local-args))
|
|
1186
|
|
1187 ;; We do have an object. Make sure it is the right type.
|
|
1188 (if ,(if (eq class eieio-default-superclass)
|
|
1189 nil ; default superclass means just an obj. Already asked.
|
|
1190 `(not (child-of-class-p (aref (car local-args) object-class)
|
|
1191 ,(list 'quote class)))
|
|
1192 )
|
|
1193
|
|
1194 ;; If not the right kind of object, call no applicable
|
|
1195 (apply 'no-applicable-method (car local-args)
|
|
1196 ,(list 'quote method) local-args)
|
|
1197
|
|
1198 ;; It is ok, do the call.
|
|
1199 ;; Fill in inter-call variables then evaluate the method.
|
|
1200 (let ((scoped-class ,(list 'quote class))
|
|
1201 (eieio-generic-call-next-method-list nil)
|
|
1202 (eieio-generic-call-key method-primary)
|
|
1203 (eieio-generic-call-methodname ,(list 'quote method))
|
|
1204 (eieio-generic-call-arglst local-args)
|
|
1205 )
|
|
1206 (apply ,(list 'quote impl) local-args)
|
|
1207 ;(,impl local-args)
|
|
1208 ))))
|
|
1209 )
|
|
1210 ))
|
|
1211
|
|
1212 (defsubst eieio-defgeneric-reset-generic-form-primary-only-one (method)
|
|
1213 "Setup METHOD to call the generic form."
|
|
1214 (let* ((doc-string (documentation method))
|
|
1215 (M (get method 'eieio-method-tree))
|
|
1216 (entry (car (aref M method-primary)))
|
|
1217 )
|
|
1218 (fset method (eieio-defgeneric-form-primary-only-one
|
|
1219 method doc-string
|
|
1220 (car entry)
|
|
1221 (cdr entry)
|
|
1222 ))))
|
|
1223
|
|
1224 (defun eieio-defgeneric (method doc-string)
|
|
1225 "Engine part to `defgeneric' macro defining METHOD with DOC-STRING."
|
|
1226 (if (and (fboundp method) (not (generic-p method))
|
|
1227 (or (byte-code-function-p (symbol-function method))
|
|
1228 (not (eq 'autoload (car (symbol-function method)))))
|
|
1229 )
|
|
1230 (error "You cannot create a generic/method over an existing symbol: %s"
|
|
1231 method))
|
|
1232 ;; Don't do this over and over.
|
|
1233 (unless (fboundp 'method)
|
|
1234 ;; This defun tells emacs where the first definition of this
|
|
1235 ;; method is defined.
|
|
1236 `(defun ,method nil)
|
|
1237 ;; Make sure the method tables are installed.
|
|
1238 (eieiomt-install method)
|
|
1239 ;; Apply the actual body of this function.
|
|
1240 (fset method (eieio-defgeneric-form method doc-string))
|
|
1241 ;; Return the method
|
|
1242 'method))
|
|
1243
|
|
1244 (defun eieio-unbind-method-implementations (method)
|
|
1245 "Make the generic method METHOD have no implementations..
|
|
1246 It will leave the original generic function in place, but remove
|
|
1247 reference to all implementations of METHOD."
|
|
1248 (put method 'eieio-method-tree nil)
|
|
1249 (put method 'eieio-method-obarray nil))
|
|
1250
|
|
1251 (defmacro defmethod (method &rest args)
|
|
1252 "Create a new METHOD through `defgeneric' with ARGS.
|
|
1253
|
|
1254 The second optional argument KEY is a specifier that
|
|
1255 modifies how the method is called, including:
|
|
1256 :before - Method will be called before the :primary
|
|
1257 :primary - The default if not specified.
|
|
1258 :after - Method will be called after the :primary
|
|
1259 :static - First arg could be an object or class
|
|
1260 The next argument is the ARGLIST. The ARGLIST specifies the arguments
|
|
1261 to the method as with `defun'. The first argument can have a type
|
|
1262 specifier, such as:
|
|
1263 ((VARNAME CLASS) ARG2 ...)
|
|
1264 where VARNAME is the name of the local variable for the method being
|
|
1265 created. The CLASS is a class symbol for a class made with `defclass'.
|
|
1266 A DOCSTRING comes after the ARGLIST, and is optional.
|
|
1267 All the rest of the args are the BODY of the method. A method will
|
|
1268 return the value of the last form in the BODY.
|
|
1269
|
|
1270 Summary:
|
|
1271
|
|
1272 (defmethod mymethod [:before | :primary | :after | :static]
|
|
1273 ((typearg class-name) arg2 &optional opt &rest rest)
|
|
1274 \"doc-string\"
|
|
1275 body)"
|
|
1276 `(eieio-defmethod (quote ,method) (quote ,args)))
|
|
1277
|
|
1278 (defun eieio-defmethod (method args)
|
|
1279 "Work part of the `defmethod' macro defining METHOD with ARGS."
|
|
1280 (let ((key nil) (body nil) (firstarg nil) (argfix nil) (argclass nil) loopa)
|
|
1281 ;; find optional keys
|
|
1282 (setq key
|
|
1283 (cond ((or (eq ':BEFORE (car args))
|
|
1284 (eq ':before (car args)))
|
|
1285 (setq args (cdr args))
|
|
1286 method-before)
|
|
1287 ((or (eq ':AFTER (car args))
|
|
1288 (eq ':after (car args)))
|
|
1289 (setq args (cdr args))
|
|
1290 method-after)
|
|
1291 ((or (eq ':PRIMARY (car args))
|
|
1292 (eq ':primary (car args)))
|
|
1293 (setq args (cdr args))
|
|
1294 method-primary)
|
|
1295 ((or (eq ':STATIC (car args))
|
|
1296 (eq ':static (car args)))
|
|
1297 (setq args (cdr args))
|
|
1298 method-static)
|
|
1299 ;; Primary key
|
|
1300 (t method-primary)))
|
|
1301 ;; get body, and fix contents of args to be the arguments of the fn.
|
|
1302 (setq body (cdr args)
|
|
1303 args (car args))
|
|
1304 (setq loopa args)
|
|
1305 ;; Create a fixed version of the arguments
|
|
1306 (while loopa
|
|
1307 (setq argfix (cons (if (listp (car loopa)) (car (car loopa)) (car loopa))
|
|
1308 argfix))
|
|
1309 (setq loopa (cdr loopa)))
|
|
1310 ;; make sure there is a generic
|
|
1311 (eieio-defgeneric
|
|
1312 method
|
|
1313 (if (stringp (car body))
|
|
1314 (car body) (format "Generically created method `%s'" method)))
|
|
1315 ;; create symbol for property to bind to. If the first arg is of
|
|
1316 ;; the form (varname vartype) and `vartype' is a class, then
|
|
1317 ;; that class will be the type symbol. If not, then it will fall
|
|
1318 ;; under the type `primary' which is a non-specific calling of the
|
|
1319 ;; function.
|
|
1320 (setq firstarg (car args))
|
|
1321 (if (listp firstarg)
|
|
1322 (progn
|
|
1323 (setq argclass (nth 1 firstarg))
|
|
1324 (if (not (class-p argclass))
|
|
1325 (error "Unknown class type %s in method parameters"
|
|
1326 (nth 1 firstarg))))
|
|
1327 (if (= key -1)
|
|
1328 (signal 'wrong-type-argument (list :static 'non-class-arg)))
|
|
1329 ;; generics are higher
|
|
1330 (setq key (+ key 3)))
|
|
1331 ;; Put this lambda into the symbol so we can find it
|
|
1332 (if (byte-code-function-p (car-safe body))
|
|
1333 (eieiomt-add method (car-safe body) key argclass)
|
|
1334 (eieiomt-add method (append (list 'lambda (reverse argfix)) body)
|
|
1335 key argclass))
|
|
1336 )
|
|
1337
|
|
1338 (when eieio-optimize-primary-methods-flag
|
|
1339 ;; Optimizing step:
|
|
1340 ;;
|
|
1341 ;; If this method, after this setup, only has primary methods, then
|
|
1342 ;; we can setup the generic that way.
|
|
1343 (if (generic-primary-only-p method)
|
|
1344 ;; If there is only one primary method, then we can go one more
|
|
1345 ;; optimization step.
|
|
1346 (if (generic-primary-only-one-p method)
|
|
1347 (eieio-defgeneric-reset-generic-form-primary-only-one method)
|
|
1348 (eieio-defgeneric-reset-generic-form-primary-only method))
|
|
1349 (eieio-defgeneric-reset-generic-form method)))
|
|
1350
|
|
1351 method)
|
|
1352
|
|
1353 ;;; Slot type validation
|
|
1354 ;;
|
|
1355 (defun eieio-perform-slot-validation (spec value)
|
|
1356 "Return non-nil if SPEC does not match VALUE."
|
|
1357 ;; typep is in cl-macs
|
|
1358 (or (eq spec t) ; t always passes
|
|
1359 (eq value eieio-unbound) ; unbound always passes
|
|
1360 (typep value spec)))
|
|
1361
|
|
1362 (defun eieio-validate-slot-value (class slot-idx value slot)
|
|
1363 "Make sure that for CLASS referencing SLOT-IDX, that VALUE is valid.
|
|
1364 Checks the :type specifier.
|
|
1365 SLOT is the slot that is being checked, and is only used when throwing
|
|
1366 and error."
|
|
1367 (if eieio-skip-typecheck
|
|
1368 nil
|
|
1369 ;; Trim off object IDX junk added in for the object index.
|
|
1370 (setq slot-idx (- slot-idx 3))
|
|
1371 (let ((st (aref (aref (class-v class) class-public-type) slot-idx)))
|
|
1372 (if (not (eieio-perform-slot-validation st value))
|
|
1373 (signal 'invalid-slot-type (list class slot st value))))))
|
|
1374
|
|
1375 (defun eieio-validate-class-slot-value (class slot-idx value slot)
|
|
1376 "Make sure that for CLASS referencing SLOT-IDX, that VALUE is valid.
|
|
1377 Checks the :type specifier.
|
|
1378 SLOT is the slot that is being checked, and is only used when throwing
|
|
1379 and error."
|
|
1380 (if eieio-skip-typecheck
|
|
1381 nil
|
|
1382 (let ((st (aref (aref (class-v class) class-class-allocation-type)
|
|
1383 slot-idx)))
|
|
1384 (if (not (eieio-perform-slot-validation st value))
|
|
1385 (signal 'invalid-slot-type (list class slot st value))))))
|
|
1386
|
|
1387 (defun eieio-barf-if-slot-unbound (value instance slotname fn)
|
|
1388 "Throw a signal if VALUE is a representation of an UNBOUND slot.
|
|
1389 INSTANCE is the object being referenced. SLOTNAME is the offending
|
|
1390 slot. If the slot is ok, return VALUE.
|
|
1391 Argument FN is the function calling this verifier."
|
|
1392 (if (and (eq value eieio-unbound) (not eieio-skip-typecheck))
|
|
1393 (slot-unbound instance (object-class instance) slotname fn)
|
|
1394 value))
|
|
1395
|
|
1396 ;;; Get/Set slots in an object.
|
|
1397 ;;
|
|
1398 (defmacro oref (obj slot)
|
|
1399 "Retrieve the value stored in OBJ in the slot named by SLOT.
|
|
1400 Slot is the name of the slot when created by `defclass' or the label
|
|
1401 created by the :initarg tag."
|
|
1402 `(eieio-oref ,obj (quote ,slot)))
|
|
1403
|
|
1404 (defun eieio-oref (obj slot)
|
|
1405 "Return the value in OBJ at SLOT in the object vector."
|
|
1406 (if (not (or (eieio-object-p obj) (class-p obj)))
|
|
1407 (signal 'wrong-type-argument (list '(or eieio-object-p class-p) obj)))
|
|
1408 (if (not (symbolp slot))
|
|
1409 (signal 'wrong-type-argument (list 'symbolp slot)))
|
|
1410 (if (class-p obj) (eieio-class-un-autoload obj))
|
|
1411 (let* ((class (if (class-p obj) obj (aref obj object-class)))
|
|
1412 (c (eieio-slot-name-index class obj slot)))
|
|
1413 (if (not c)
|
|
1414 ;; It might be missing because it is a :class allocated slot.
|
|
1415 ;; Lets check that info out.
|
|
1416 (if (setq c (eieio-class-slot-name-index class slot))
|
|
1417 ;; Oref that slot.
|
|
1418 (aref (aref (class-v class) class-class-allocation-values) c)
|
|
1419 ;; The slot-missing method is a cool way of allowing an object author
|
|
1420 ;; to intercept missing slot definitions. Since it is also the LAST
|
|
1421 ;; thing called in this fn, it's return value would be retrieved.
|
|
1422 (slot-missing obj slot 'oref)
|
|
1423 ;;(signal 'invalid-slot-name (list (object-name obj) slot))
|
|
1424 )
|
|
1425 (if (not (eieio-object-p obj))
|
|
1426 (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
|
1427 (eieio-barf-if-slot-unbound (aref obj c) obj slot 'oref))))
|
|
1428
|
|
1429 (defalias 'slot-value 'eieio-oref)
|
|
1430 (defalias 'set-slot-value 'eieio-oset)
|
|
1431
|
|
1432 (defmacro oref-default (obj slot)
|
|
1433 "Gets the default value of OBJ (maybe a class) for SLOT.
|
|
1434 The default value is the value installed in a class with the :initform
|
|
1435 tag. SLOT can be the slot name, or the tag specified by the :initarg
|
|
1436 tag in the `defclass' call."
|
|
1437 `(eieio-oref-default ,obj (quote ,slot)))
|
|
1438
|
|
1439 (defun eieio-oref-default (obj slot)
|
|
1440 "Does the work for the macro `oref-default' with similar parameters.
|
|
1441 Fills in OBJ's SLOT with it's default value."
|
|
1442 (if (not (or (eieio-object-p obj) (class-p obj))) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
|
1443 (if (not (symbolp slot)) (signal 'wrong-type-argument (list 'symbolp slot)))
|
|
1444 (let* ((cl (if (eieio-object-p obj) (aref obj object-class) obj))
|
|
1445 (c (eieio-slot-name-index cl obj slot)))
|
|
1446 (if (not c)
|
|
1447 ;; It might be missing because it is a :class allocated slot.
|
|
1448 ;; Lets check that info out.
|
|
1449 (if (setq c
|
|
1450 (eieio-class-slot-name-index cl slot))
|
|
1451 ;; Oref that slot.
|
|
1452 (aref (aref (class-v cl) class-class-allocation-values)
|
|
1453 c)
|
|
1454 (slot-missing obj slot 'oref-default)
|
|
1455 ;;(signal 'invalid-slot-name (list (class-name cl) slot))
|
|
1456 )
|
|
1457 (eieio-barf-if-slot-unbound
|
|
1458 (let ((val (nth (- c 3) (aref (class-v cl) class-public-d))))
|
|
1459 (eieio-default-eval-maybe val))
|
|
1460 obj cl 'oref-default))))
|
|
1461
|
|
1462 (defun eieio-default-eval-maybe (val)
|
|
1463 "Check VAL, and return what `oref-default' would provide."
|
|
1464 ;; check for quoted things, and unquote them
|
|
1465 (if (and (listp val) (eq (car val) 'quote))
|
|
1466 (car (cdr val))
|
|
1467 ;; return it verbatim
|
|
1468 val))
|
|
1469
|
|
1470 ;;; Object Set macros
|
|
1471 ;;
|
|
1472 (defmacro oset (obj slot value)
|
|
1473 "Set the value in OBJ for slot SLOT to VALUE.
|
|
1474 SLOT is the slot name as specified in `defclass' or the tag created
|
|
1475 with in the :initarg slot. VALUE can be any Lisp object."
|
|
1476 `(eieio-oset ,obj (quote ,slot) ,value))
|
|
1477
|
|
1478 (defun eieio-oset (obj slot value)
|
|
1479 "Does the work for the macro `oset'.
|
|
1480 Fills in OBJ's SLOT with VALUE."
|
|
1481 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
|
1482 (if (not (symbolp slot)) (signal 'wrong-type-argument (list 'symbolp slot)))
|
|
1483 (let ((c (eieio-slot-name-index (object-class-fast obj) obj slot)))
|
|
1484 (if (not c)
|
|
1485 ;; It might be missing because it is a :class allocated slot.
|
|
1486 ;; Lets check that info out.
|
|
1487 (if (setq c
|
|
1488 (eieio-class-slot-name-index (aref obj object-class) slot))
|
|
1489 ;; Oset that slot.
|
|
1490 (progn
|
|
1491 (eieio-validate-class-slot-value (object-class-fast obj) c value slot)
|
|
1492 (aset (aref (class-v (aref obj object-class))
|
|
1493 class-class-allocation-values)
|
|
1494 c value))
|
|
1495 ;; See oref for comment on `slot-missing'
|
|
1496 (slot-missing obj slot 'oset value)
|
|
1497 ;;(signal 'invalid-slot-name (list (object-name obj) slot))
|
|
1498 )
|
|
1499 (eieio-validate-slot-value (object-class-fast obj) c value slot)
|
|
1500 (aset obj c value))))
|
|
1501
|
|
1502 (defmacro oset-default (class slot value)
|
|
1503 "Set the default slot in CLASS for SLOT to VALUE.
|
|
1504 The default value is usually set with the :initform tag during class
|
|
1505 creation. This allows users to change the default behavior of classes
|
|
1506 after they are created."
|
|
1507 `(eieio-oset-default ,class (quote ,slot) ,value))
|
|
1508
|
|
1509 (defun eieio-oset-default (class slot value)
|
|
1510 "Does the work for the macro `oset-default'.
|
|
1511 Fills in the default value in CLASS' in SLOT with VALUE."
|
|
1512 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
|
|
1513 (if (not (symbolp slot)) (signal 'wrong-type-argument (list 'symbolp slot)))
|
|
1514 (let* ((scoped-class class)
|
|
1515 (c (eieio-slot-name-index class nil slot)))
|
|
1516 (if (not c)
|
|
1517 ;; It might be missing because it is a :class allocated slot.
|
|
1518 ;; Lets check that info out.
|
|
1519 (if (setq c (eieio-class-slot-name-index class slot))
|
|
1520 (progn
|
|
1521 ;; Oref that slot.
|
|
1522 (eieio-validate-class-slot-value class c value slot)
|
|
1523 (aset (aref (class-v class) class-class-allocation-values) c
|
|
1524 value))
|
|
1525 (signal 'invalid-slot-name (list (class-name class) slot)))
|
|
1526 (eieio-validate-slot-value class c value slot)
|
|
1527 ;; Set this into the storage for defaults.
|
|
1528 (setcar (nthcdr (- c 3) (aref (class-v class) class-public-d))
|
|
1529 value)
|
|
1530 ;; Take the value, and put it into our cache object.
|
|
1531 (eieio-oset (aref (class-v class) class-default-object-cache)
|
|
1532 slot value)
|
|
1533 )))
|
|
1534
|
|
1535 ;;; Handy CLOS macros
|
|
1536 ;;
|
|
1537 (defmacro with-slots (spec-list object &rest body)
|
|
1538 "Bind SPEC-LIST lexically to slot values in OBJECT, and execute BODY.
|
|
1539 This establishes a lexical environment for referring to the slots in
|
|
1540 the instance named by the given slot-names as though they were
|
|
1541 variables. Within such a context the value of the slot can be
|
|
1542 specified by using its slot name, as if it were a lexically bound
|
|
1543 variable. Both setf and setq can be used to set the value of the
|
|
1544 slot.
|
|
1545
|
|
1546 SPEC-LIST is of a form similar to `let'. For example:
|
|
1547
|
|
1548 ((VAR1 SLOT1)
|
|
1549 SLOT2
|
|
1550 SLOTN
|
|
1551 (VARN+1 SLOTN+1))
|
|
1552
|
|
1553 Where each VAR is the local variable given to the associated
|
|
1554 SLOT. A Slot specified without a variable name is given a
|
|
1555 variable name of the same name as the slot."
|
|
1556 ;; Transform the spec-list into a symbol-macrolet spec-list.
|
|
1557 (let ((mappings (mapcar (lambda (entry)
|
|
1558 (let ((var (if (listp entry) (car entry) entry))
|
|
1559 (slot (if (listp entry) (cadr entry) entry)))
|
|
1560 (list var `(slot-value ,object ',slot))))
|
|
1561 spec-list)))
|
|
1562 (append (list 'symbol-macrolet mappings)
|
|
1563 body)))
|
|
1564 (put 'with-slots 'lisp-indent-function 2)
|
|
1565
|
|
1566
|
|
1567 ;;; Simple generators, and query functions. None of these would do
|
|
1568 ;; well embedded into an object.
|
|
1569 ;;
|
|
1570 (defmacro object-class-fast (obj) "Return the class struct defining OBJ with no check."
|
|
1571 `(aref ,obj object-class))
|
|
1572
|
|
1573 (defun class-name (class) "Return a Lisp like symbol name for CLASS."
|
|
1574 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
|
|
1575 ;; I think this is supposed to return a symbol, but to me CLASS is a symbol,
|
|
1576 ;; and I wanted a string. Arg!
|
|
1577 (format "#<class %s>" (symbol-name class)))
|
|
1578
|
|
1579 (defun object-name (obj &optional extra)
|
|
1580 "Return a Lisp like symbol string for object OBJ.
|
|
1581 If EXTRA, include that in the string returned to represent the symbol."
|
|
1582 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
|
1583 (format "#<%s %s%s>" (symbol-name (object-class-fast obj))
|
|
1584 (aref obj object-name) (or extra "")))
|
|
1585
|
|
1586 (defun object-name-string (obj) "Return a string which is OBJ's name."
|
|
1587 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
|
1588 (aref obj object-name))
|
|
1589
|
|
1590 (defun object-set-name-string (obj name) "Set the string which is OBJ's NAME."
|
|
1591 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
|
1592 (if (not (stringp name)) (signal 'wrong-type-argument (list 'stringp name)))
|
|
1593 (aset obj object-name name))
|
|
1594
|
|
1595 (defun object-class (obj) "Return the class struct defining OBJ."
|
|
1596 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
|
1597 (object-class-fast obj))
|
|
1598 (defalias 'class-of 'object-class)
|
|
1599
|
|
1600 (defun object-class-name (obj) "Return a Lisp like symbol name for OBJ's class."
|
|
1601 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
|
1602 (class-name (object-class-fast obj)))
|
|
1603
|
|
1604 (defmacro class-parents-fast (class) "Return parent classes to CLASS with no check."
|
|
1605 `(aref (class-v ,class) class-parent))
|
|
1606
|
|
1607 (defun class-parents (class)
|
|
1608 "Return parent classes to CLASS. (overload of variable).
|
|
1609
|
|
1610 The CLOS function `class-direct-superclasses' is aliased to this function."
|
|
1611 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
|
|
1612 (class-parents-fast class))
|
|
1613
|
|
1614 (defmacro class-children-fast (class) "Return child classes to CLASS with no check."
|
|
1615 `(aref (class-v ,class) class-children))
|
|
1616
|
|
1617 (defun class-children (class)
|
|
1618 "Return child classses to CLASS.
|
|
1619
|
|
1620 The CLOS function `class-direct-subclasses' is aliased to this function."
|
|
1621 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
|
|
1622 (class-children-fast class))
|
|
1623
|
|
1624 ;; Official CLOS functions.
|
|
1625 (defalias 'class-direct-superclasses 'class-parents)
|
|
1626 (defalias 'class-direct-subclasses 'class-children)
|
|
1627
|
|
1628 (defmacro class-parent-fast (class) "Return first parent class to CLASS with no check."
|
|
1629 `(car (class-parents-fast ,class)))
|
|
1630
|
|
1631 (defmacro class-parent (class) "Return first parent class to CLASS. (overload of variable)."
|
|
1632 `(car (class-parents ,class)))
|
|
1633
|
|
1634 (defmacro same-class-fast-p (obj class) "Return t if OBJ is of class-type CLASS with no error checking."
|
|
1635 `(eq (aref ,obj object-class) ,class))
|
|
1636
|
|
1637 (defun same-class-p (obj class) "Return t if OBJ is of class-type CLASS."
|
|
1638 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
|
|
1639 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
|
1640 (same-class-fast-p obj class))
|
|
1641
|
|
1642 (defun object-of-class-p (obj class)
|
|
1643 "Return non-nil if OBJ is an instance of CLASS or CLASS' subclasses."
|
|
1644 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
|
1645 ;; class will be checked one layer down
|
|
1646 (child-of-class-p (aref obj object-class) class))
|
|
1647 ;; Backwards compatibility
|
|
1648 (defalias 'obj-of-class-p 'object-of-class-p)
|
|
1649
|
|
1650 (defun child-of-class-p (child class)
|
|
1651 "If CHILD class is a subclass of CLASS."
|
|
1652 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
|
|
1653 (if (not (class-p child)) (signal 'wrong-type-argument (list 'class-p child)))
|
|
1654 (let ((p nil))
|
|
1655 (while (and child (not (eq child class)))
|
|
1656 (setq p (append p (aref (class-v child) class-parent))
|
|
1657 child (car p)
|
|
1658 p (cdr p)))
|
|
1659 (if child t)))
|
|
1660
|
|
1661 (defun object-slots (obj) "List of slots available in OBJ."
|
|
1662 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
|
1663 (aref (class-v (object-class-fast obj)) class-public-a))
|
|
1664
|
|
1665 (defun class-slot-initarg (class slot) "Fetch from CLASS, SLOT's :initarg."
|
|
1666 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
|
|
1667 (let ((ia (aref (class-v class) class-initarg-tuples))
|
|
1668 (f nil))
|
|
1669 (while (and ia (not f))
|
|
1670 (if (eq (cdr (car ia)) slot)
|
|
1671 (setq f (car (car ia))))
|
|
1672 (setq ia (cdr ia)))
|
|
1673 f))
|
|
1674
|
|
1675 ;;; CLOS queries into classes and slots
|
|
1676 ;;
|
|
1677 (defun slot-boundp (object slot)
|
|
1678 "Non-nil if OBJECT's SLOT is bound.
|
|
1679 Setting a slot's value makes it bound. Calling `slot-makeunbound' will
|
|
1680 make a slot unbound.
|
|
1681 OBJECT can be an instance or a class."
|
|
1682 ;; Skip typechecking while retrieving this value.
|
|
1683 (let ((eieio-skip-typecheck t))
|
|
1684 ;; Return nil if the magic symbol is in there.
|
|
1685 (if (eieio-object-p object)
|
|
1686 (if (eq (eieio-oref object slot) eieio-unbound) nil t)
|
|
1687 (if (class-p object)
|
|
1688 (if (eq (eieio-oref-default object slot) eieio-unbound) nil t)
|
|
1689 (signal 'wrong-type-argument (list 'eieio-object-p object))))))
|
|
1690
|
|
1691 (defun slot-makeunbound (object slot)
|
|
1692 "In OBJECT, make SLOT unbound."
|
|
1693 (eieio-oset object slot eieio-unbound))
|
|
1694
|
|
1695 (defun slot-exists-p (object-or-class slot)
|
|
1696 "Non-nil if OBJECT-OR-CLASS has SLOT."
|
|
1697 (let ((cv (class-v (cond ((eieio-object-p object-or-class)
|
|
1698 (object-class object-or-class))
|
|
1699 ((class-p object-or-class)
|
|
1700 object-or-class))
|
|
1701 )))
|
|
1702 (or (memq slot (aref cv class-public-a))
|
|
1703 (memq slot (aref cv class-class-allocation-a)))
|
|
1704 ))
|
|
1705
|
|
1706 (defun find-class (symbol &optional errorp)
|
|
1707 "Return the class that SYMBOL represents.
|
|
1708 If there is no class, nil is returned if ERRORP is nil.
|
|
1709 If ERRORP is non-nil, `wrong-argument-type' is signaled."
|
|
1710 (if (not (class-p symbol))
|
|
1711 (if errorp (signal 'wrong-type-argument (list 'class-p symbol))
|
|
1712 nil)
|
|
1713 (class-v symbol)))
|
|
1714
|
|
1715 ;;; Slightly more complex utility functions for objects
|
|
1716 ;;
|
|
1717 (defun object-assoc (key slot list)
|
|
1718 "Return an object if KEY is `equal' to SLOT's value of an object in LIST.
|
|
1719 LIST is a list of objects who's slots are searched.
|
|
1720 Objects in LIST do not need to have a slot named SLOT, nor does
|
|
1721 SLOT need to be bound. If these errors occur, those objects will
|
|
1722 be ignored."
|
|
1723 (if (not (listp list)) (signal 'wrong-type-argument (list 'listp list)))
|
|
1724 (while (and list (not (condition-case nil
|
|
1725 ;; This prevents errors for missing slots.
|
|
1726 (equal key (eieio-oref (car list) slot))
|
|
1727 (error nil))))
|
|
1728 (setq list (cdr list)))
|
|
1729 (car list))
|
|
1730
|
|
1731 (defun object-assoc-list (slot list)
|
|
1732 "Return an association list with the contents of SLOT as the key element.
|
|
1733 LIST must be a list of objects with SLOT in it.
|
|
1734 This is useful when you need to do completing read on an object group."
|
|
1735 (if (not (listp list)) (signal 'wrong-type-argument (list 'listp list)))
|
|
1736 (let ((assoclist nil))
|
|
1737 (while list
|
|
1738 (setq assoclist (cons (cons (eieio-oref (car list) slot)
|
|
1739 (car list))
|
|
1740 assoclist))
|
|
1741 (setq list (cdr list)))
|
|
1742 (nreverse assoclist)))
|
|
1743
|
|
1744 (defun object-assoc-list-safe (slot list)
|
|
1745 "Return an association list with the contents of SLOT as the key element.
|
|
1746 LIST must be a list of objects, but those objects do not need to have
|
|
1747 SLOT in it. If it does not, then that element is left out of the association
|
|
1748 list."
|
|
1749 (if (not (listp list)) (signal 'wrong-type-argument (list 'listp list)))
|
|
1750 (let ((assoclist nil))
|
|
1751 (while list
|
|
1752 (if (slot-exists-p (car list) slot)
|
|
1753 (setq assoclist (cons (cons (eieio-oref (car list) slot)
|
|
1754 (car list))
|
|
1755 assoclist)))
|
|
1756 (setq list (cdr list)))
|
|
1757 (nreverse assoclist)))
|
|
1758
|
|
1759 (defun object-add-to-list (object slot item &optional append)
|
|
1760 "In OBJECT's SLOT, add ITEM to the list of elements.
|
|
1761 Optional argument APPEND indicates we need to append to the list.
|
|
1762 If ITEM already exists in the list in SLOT, then it is not added.
|
|
1763 Comparison is done with `equal' through the `member' function call.
|
|
1764 If SLOT is unbound, bind it to the list containing ITEM."
|
|
1765 (let (ov)
|
|
1766 ;; Find the originating list.
|
|
1767 (if (not (slot-boundp object slot))
|
|
1768 (setq ov (list item))
|
|
1769 (setq ov (eieio-oref object slot))
|
|
1770 ;; turn it into a list.
|
|
1771 (unless (listp ov)
|
|
1772 (setq ov (list ov)))
|
|
1773 ;; Do the combination
|
|
1774 (if (not (member item ov))
|
|
1775 (setq ov
|
|
1776 (if append
|
|
1777 (append ov (list item))
|
|
1778 (cons item ov)))))
|
|
1779 ;; Set back into the slot.
|
|
1780 (eieio-oset object slot ov)))
|
|
1781
|
|
1782 (defun object-remove-from-list (object slot item)
|
|
1783 "In OBJECT's SLOT, remove occurrences of ITEM.
|
|
1784 Deletion is done with `delete', which deletes by side effect
|
|
1785 and comparisons are done with `equal'.
|
|
1786 If SLOT is unbound, do nothing."
|
|
1787 (if (not (slot-boundp object slot))
|
|
1788 nil
|
|
1789 (eieio-oset object slot (delete item (eieio-oref object slot)))))
|
|
1790
|
|
1791 ;;; EIEIO internal search functions
|
|
1792 ;;
|
|
1793 (defun eieio-slot-originating-class-p (start-class slot)
|
|
1794 "Return Non-nil if START-CLASS is the first class to define SLOT.
|
|
1795 This is for testing if `scoped-class' is the class that defines SLOT
|
|
1796 so that we can protect private slots."
|
|
1797 (let ((par (class-parents start-class))
|
|
1798 (ret t))
|
|
1799 (if (not par)
|
|
1800 t
|
|
1801 (while (and par ret)
|
|
1802 (if (intern-soft (symbol-name slot)
|
|
1803 (aref (class-v (car par))
|
|
1804 class-symbol-obarray))
|
|
1805 (setq ret nil))
|
|
1806 (setq par (cdr par)))
|
|
1807 ret)))
|
|
1808
|
|
1809 (defun eieio-slot-name-index (class obj slot)
|
|
1810 "In CLASS for OBJ find the index of the named SLOT.
|
|
1811 The slot is a symbol which is installed in CLASS by the `defclass'
|
|
1812 call. OBJ can be nil, but if it is an object, and the slot in question
|
|
1813 is protected, access will be allowed if obj is a child of the currently
|
|
1814 `scoped-class'.
|
|
1815 If SLOT is the value created with :initarg instead,
|
|
1816 reverse-lookup that name, and recurse with the associated slot value."
|
|
1817 ;; Removed checks to outside this call
|
|
1818 (let* ((fsym (intern-soft (symbol-name slot)
|
|
1819 (aref (class-v class)
|
|
1820 class-symbol-obarray)))
|
|
1821 (fsi (if (symbolp fsym) (symbol-value fsym) nil)))
|
|
1822 (if (integerp fsi)
|
|
1823 (cond
|
|
1824 ((not (get fsym 'protection))
|
|
1825 (+ 3 fsi))
|
|
1826 ((and (eq (get fsym 'protection) 'protected)
|
|
1827 scoped-class
|
|
1828 (or (child-of-class-p class scoped-class)
|
|
1829 (and (eieio-object-p obj)
|
|
1830 (child-of-class-p class (object-class obj)))))
|
|
1831 (+ 3 fsi))
|
|
1832 ((and (eq (get fsym 'protection) 'private)
|
|
1833 (or (and scoped-class
|
|
1834 (eieio-slot-originating-class-p scoped-class slot))
|
|
1835 eieio-initializing-object))
|
|
1836 (+ 3 fsi))
|
|
1837 (t nil))
|
|
1838 (let ((fn (eieio-initarg-to-attribute class slot)))
|
|
1839 (if fn (eieio-slot-name-index class obj fn) nil)))))
|
|
1840
|
|
1841 (defun eieio-class-slot-name-index (class slot)
|
|
1842 "In CLASS find the index of the named SLOT.
|
|
1843 The slot is a symbol which is installed in CLASS by the `defclass'
|
|
1844 call. If SLOT is the value created with :initarg instead,
|
|
1845 reverse-lookup that name, and recurse with the associated slot value."
|
|
1846 ;; This will happen less often, and with fewer slots. Do this the
|
|
1847 ;; storage cheap way.
|
|
1848 (let* ((a (aref (class-v class) class-class-allocation-a))
|
|
1849 (l1 (length a))
|
|
1850 (af (memq slot a))
|
|
1851 (l2 (length af)))
|
|
1852 ;; Slot # is length of the total list, minus the remaining list of
|
|
1853 ;; the found slot.
|
|
1854 (if af (- l1 l2))))
|
|
1855
|
|
1856 ;;; CLOS generics internal function handling
|
|
1857 ;;
|
|
1858 (defvar eieio-generic-call-methodname nil
|
|
1859 "When using `call-next-method', provides a context on how to do it.")
|
|
1860 (defvar eieio-generic-call-arglst nil
|
|
1861 "When using `call-next-method', provides a context for parameters.")
|
|
1862 (defvar eieio-generic-call-key nil
|
|
1863 "When using `call-next-method', provides a context for the current key.
|
|
1864 Keys are a number representing :before, :primary, and :after methods.")
|
|
1865 (defvar eieio-generic-call-next-method-list nil
|
|
1866 "When executing a PRIMARY or STATIC method, track the 'next-method'.
|
|
1867 During executions, the list is first generated, then as each next method
|
|
1868 is called, the next method is popped off the stack.")
|
|
1869
|
|
1870 (defvar eieio-pre-method-execution-hooks nil
|
|
1871 "*Hooks run just before a method is executed.
|
|
1872 The hook function must accept on argument, this list of forms
|
|
1873 about to be executed.")
|
|
1874
|
|
1875 (defun eieio-generic-call (method args)
|
|
1876 "Call METHOD with ARGS.
|
|
1877 ARGS provides the context on which implementation to use.
|
|
1878 This should only be called from a generic function."
|
|
1879 ;; We must expand our arguments first as they are always
|
|
1880 ;; passed in as quoted symbols
|
|
1881 (let ((newargs nil) (mclass nil) (lambdas nil) (tlambdas nil) (keys nil)
|
|
1882 (eieio-generic-call-methodname method)
|
|
1883 (eieio-generic-call-arglst args)
|
|
1884 (firstarg nil)
|
|
1885 (primarymethodlist nil))
|
|
1886 ;; get a copy
|
|
1887 (setq newargs args
|
|
1888 firstarg (car newargs))
|
|
1889 ;; Is the class passed in autoloaded?
|
|
1890 ;; Since class names are also constructors, they can be autoloaded
|
|
1891 ;; via the autoload command. Check for this, and load them in.
|
|
1892 ;; It's ok if it doesn't turn out to be a class. Probably want that
|
|
1893 ;; function loaded anyway.
|
|
1894 (if (and (symbolp firstarg)
|
|
1895 (fboundp firstarg)
|
|
1896 (listp (symbol-function firstarg))
|
|
1897 (eq 'autoload (car (symbol-function firstarg))))
|
|
1898 (load (nth 1 (symbol-function firstarg))))
|
|
1899 ;; Determine the class to use.
|
|
1900 (cond ((eieio-object-p firstarg)
|
|
1901 (setq mclass (object-class-fast firstarg)))
|
|
1902 ((class-p firstarg)
|
|
1903 (setq mclass firstarg))
|
|
1904 )
|
|
1905 ;; Make sure the class is a valid class
|
|
1906 ;; mclass can be nil (meaning a generic for should be used.
|
|
1907 ;; mclass cannot have a value that is not a class, however.
|
|
1908 (when (and (not (null mclass)) (not (class-p mclass)))
|
|
1909 (error "Cannot dispatch method %S on class %S"
|
|
1910 method mclass)
|
|
1911 )
|
|
1912 ;; Now create a list in reverse order of all the calls we have
|
|
1913 ;; make in order to successfully do this right. Rules:
|
|
1914 ;; 1) Only call generics if scoped-class is not defined
|
|
1915 ;; This prevents multiple calls in the case of recursion
|
|
1916 ;; 2) Only call static if this is a static method.
|
|
1917 ;; 3) Only call specifics if the definition allows for them.
|
|
1918 ;; 4) Call in order based on :before, :primary, and :after
|
|
1919 (when (eieio-object-p firstarg)
|
|
1920 ;; Non-static calls do all this stuff.
|
|
1921
|
|
1922 ;; :after methods
|
|
1923 (setq tlambdas
|
|
1924 (if mclass
|
|
1925 (eieiomt-method-list method method-after mclass)
|
|
1926 (list (eieio-generic-form method method-after nil)))
|
|
1927 ;;(or (and mclass (eieio-generic-form method method-after mclass))
|
|
1928 ;; (eieio-generic-form method method-after nil))
|
|
1929 )
|
|
1930 (setq lambdas (append tlambdas lambdas)
|
|
1931 keys (append (make-list (length tlambdas) method-after) keys))
|
|
1932
|
|
1933 ;; :primary methods
|
|
1934 (setq tlambdas
|
|
1935 (or (and mclass (eieio-generic-form method method-primary mclass))
|
|
1936 (eieio-generic-form method method-primary nil)))
|
|
1937 (when tlambdas
|
|
1938 (setq lambdas (cons tlambdas lambdas)
|
|
1939 keys (cons method-primary keys)
|
|
1940 primarymethodlist
|
|
1941 (eieiomt-method-list method method-primary mclass)))
|
|
1942
|
|
1943 ;; :before methods
|
|
1944 (setq tlambdas
|
|
1945 (if mclass
|
|
1946 (eieiomt-method-list method method-before mclass)
|
|
1947 (list (eieio-generic-form method method-before nil)))
|
|
1948 ;;(or (and mclass (eieio-generic-form method method-before mclass))
|
|
1949 ;; (eieio-generic-form method method-before nil))
|
|
1950 )
|
|
1951 (setq lambdas (append tlambdas lambdas)
|
|
1952 keys (append (make-list (length tlambdas) method-before) keys))
|
|
1953 )
|
|
1954
|
|
1955 ;; If there were no methods found, then there could be :static methods.
|
|
1956 (when (not lambdas)
|
|
1957 (setq tlambdas
|
|
1958 (eieio-generic-form method method-static mclass))
|
|
1959 (setq lambdas (cons tlambdas lambdas)
|
|
1960 keys (cons method-static keys)
|
|
1961 primarymethodlist ;; Re-use even with bad name here
|
|
1962 (eieiomt-method-list method method-static mclass)))
|
|
1963
|
|
1964 (run-hook-with-args 'eieio-pre-method-execution-hooks
|
|
1965 primarymethodlist)
|
|
1966
|
|
1967 ;; Now loop through all occurances forms which we must execute
|
|
1968 ;; (which are happily sorted now) and execute them all!
|
|
1969 (let ((rval nil) (lastval nil) (rvalever nil) (found nil))
|
|
1970 (while lambdas
|
|
1971 (if (car lambdas)
|
|
1972 (let* ((scoped-class (cdr (car lambdas)))
|
|
1973 (eieio-generic-call-key (car keys))
|
|
1974 (has-return-val
|
|
1975 (or (= eieio-generic-call-key method-primary)
|
|
1976 (= eieio-generic-call-key method-static)))
|
|
1977 (eieio-generic-call-next-method-list
|
|
1978 ;; Use the cdr, as the first element is the fcn
|
|
1979 ;; we are calling right now.
|
|
1980 (when has-return-val (cdr primarymethodlist)))
|
|
1981 )
|
|
1982 (setq found t)
|
|
1983 ;;(setq rval (apply (car (car lambdas)) newargs))
|
|
1984 (setq lastval (apply (car (car lambdas)) newargs))
|
|
1985 (when has-return-val
|
|
1986 (setq rval lastval
|
|
1987 rvalever t))
|
|
1988 ))
|
|
1989 (setq lambdas (cdr lambdas)
|
|
1990 keys (cdr keys)))
|
|
1991 (if (not found)
|
|
1992 (if (eieio-object-p (car args))
|
|
1993 (setq rval (apply 'no-applicable-method (car args) method args)
|
|
1994 rvalever t)
|
|
1995 (signal
|
|
1996 'no-method-definition
|
|
1997 (list method args))))
|
|
1998 ;; Right Here... it could be that lastval is returned when
|
|
1999 ;; rvalever is nil. Is that right?
|
|
2000 rval)))
|
|
2001
|
|
2002 (defun eieio-generic-call-primary-only (method args)
|
|
2003 "Call METHOD with ARGS for methods with only :PRIMARY implementations.
|
|
2004 ARGS provides the context on which implementation to use.
|
|
2005 This should only be called from a generic function.
|
|
2006
|
|
2007 This method is like `eieio-generic-call', but only
|
|
2008 implementations in the :PRIMARY slot are queried. After many
|
|
2009 years of use, it appears that over 90% of methods in use
|
|
2010 have :PRIMARY implementations only. We can therefore optimize
|
|
2011 for this common case to improve performance."
|
|
2012 ;; We must expand our arguments first as they are always
|
|
2013 ;; passed in as quoted symbols
|
|
2014 (let ((newargs nil) (mclass nil) (lambdas nil)
|
|
2015 (eieio-generic-call-methodname method)
|
|
2016 (eieio-generic-call-arglst args)
|
|
2017 (firstarg nil)
|
|
2018 (primarymethodlist nil)
|
|
2019 )
|
|
2020 ;; get a copy
|
|
2021 (setq newargs args
|
|
2022 firstarg (car newargs))
|
|
2023
|
|
2024 ;; Determine the class to use.
|
|
2025 (cond ((eieio-object-p firstarg)
|
|
2026 (setq mclass (object-class-fast firstarg)))
|
|
2027 ((not firstarg)
|
|
2028 (error "Method %s called on nil" method))
|
|
2029 ((not (eieio-object-p firstarg))
|
|
2030 (error "Primary-only method %s called on something not an object" method))
|
|
2031 (t
|
|
2032 (error "EIEIO Error: Improperly classified method %s as primary only"
|
|
2033 method)
|
|
2034 ))
|
|
2035 ;; Make sure the class is a valid class
|
|
2036 ;; mclass can be nil (meaning a generic for should be used.
|
|
2037 ;; mclass cannot have a value that is not a class, however.
|
|
2038 (when (null mclass)
|
|
2039 (error "Cannot dispatch method %S on class %S" method mclass)
|
|
2040 )
|
|
2041
|
|
2042 ;; :primary methods
|
|
2043 (setq lambdas (eieio-generic-form method method-primary mclass))
|
|
2044 (setq primarymethodlist ;; Re-use even with bad name here
|
|
2045 (eieiomt-method-list method method-primary mclass))
|
|
2046
|
|
2047 ;; Now loop through all occurances forms which we must execute
|
|
2048 ;; (which are happily sorted now) and execute them all!
|
|
2049 (let* ((rval nil) (lastval nil) (rvalever nil)
|
|
2050 (scoped-class (cdr lambdas))
|
|
2051 (eieio-generic-call-key method-primary)
|
|
2052 ;; Use the cdr, as the first element is the fcn
|
|
2053 ;; we are calling right now.
|
|
2054 (eieio-generic-call-next-method-list (cdr primarymethodlist))
|
|
2055 )
|
|
2056
|
|
2057 (if (or (not lambdas) (not (car lambdas)))
|
|
2058
|
|
2059 ;; No methods found for this impl...
|
|
2060 (if (eieio-object-p (car args))
|
|
2061 (setq rval (apply 'no-applicable-method (car args) method args)
|
|
2062 rvalever t)
|
|
2063 (signal
|
|
2064 'no-method-definition
|
|
2065 (list method args)))
|
|
2066
|
|
2067 ;; Do the regular implementation here.
|
|
2068
|
|
2069 (run-hook-with-args 'eieio-pre-method-execution-hooks
|
|
2070 lambdas)
|
|
2071
|
|
2072 (setq lastval (apply (car lambdas) newargs))
|
|
2073 (setq rval lastval
|
|
2074 rvalever t)
|
|
2075 )
|
|
2076
|
|
2077 ;; Right Here... it could be that lastval is returned when
|
|
2078 ;; rvalever is nil. Is that right?
|
|
2079 rval)))
|
|
2080
|
|
2081 (defun eieiomt-method-list (method key class)
|
|
2082 "Return an alist list of methods lambdas.
|
|
2083 METHOD is the method name.
|
|
2084 KEY represents either :before, or :after methods.
|
|
2085 CLASS is the starting class to search from in the method tree.
|
|
2086 If CLASS is nil, then an empty list of methods should be returned."
|
|
2087 ;; Note: eieiomt - the MT means MethodTree. See more comments below
|
|
2088 ;; for the rest of the eieiomt methods.
|
|
2089 (let ((lambdas nil)
|
|
2090 (mclass (list class)))
|
|
2091 (while mclass
|
|
2092 ;; Note: a nil can show up in the class list once we start
|
|
2093 ;; searching through the method tree.
|
|
2094 (when (car mclass)
|
|
2095 ;; lookup the form to use for the PRIMARY object for the next level
|
|
2096 (let ((tmpl (eieio-generic-form method key (car mclass))))
|
|
2097 (when (or (not lambdas)
|
|
2098 ;; This prevents duplicates coming out of the
|
|
2099 ;; class method optimizer. Perhaps we should
|
|
2100 ;; just not optimize before/afters?
|
|
2101 (not (eq (car tmpl) (car (car lambdas)))))
|
|
2102 (setq lambdas (cons tmpl lambdas))
|
|
2103 (if (null (car lambdas))
|
|
2104 (setq lambdas (cdr lambdas))))))
|
|
2105 ;; Add new classes to mclass. Since our input might not be a class
|
|
2106 ;; protect against that.
|
|
2107 (if (car mclass)
|
|
2108 ;; If there is a class, append any methods it may provide
|
|
2109 ;; to the remainder of the class list.
|
|
2110 (let ((io (class-method-invocation-order (car mclass))))
|
|
2111 (if (eq io :depth-first)
|
|
2112 ;; Depth first.
|
|
2113 (setq mclass (append (eieiomt-next (car mclass)) (cdr mclass)))
|
|
2114 ;; Breadth first.
|
|
2115 (setq mclass (append (cdr mclass) (eieiomt-next (car mclass)))))
|
|
2116 )
|
|
2117 ;; Advance to next entry in mclass if it is nil.
|
|
2118 (setq mclass (cdr mclass)))
|
|
2119 )
|
|
2120 (if (eq key method-after)
|
|
2121 lambdas
|
|
2122 (nreverse lambdas))))
|
|
2123
|
|
2124 (defun next-method-p ()
|
|
2125 "Non-nil if there is a next method.
|
|
2126 Returns a list of lambda expressions which is the `next-method'
|
|
2127 order."
|
|
2128 eieio-generic-call-next-method-list)
|
|
2129
|
|
2130 (defun call-next-method (&rest replacement-args)
|
|
2131 "Call the superclass method from a subclass method.
|
|
2132 The superclass method is specified in the current method list,
|
|
2133 and is called the next method.
|
|
2134
|
|
2135 If REPLACEMENT-ARGS is non-nil, then use them instead of
|
|
2136 `eieio-generic-call-arglst'. The generic arg list are the
|
|
2137 arguments passed in at the top level.
|
|
2138
|
|
2139 Use `next-method-p' to find out if there is a next method to call."
|
|
2140 (if (not scoped-class)
|
|
2141 (error "Call-next-method not called within a class specific method"))
|
|
2142 (if (and (/= eieio-generic-call-key method-primary)
|
|
2143 (/= eieio-generic-call-key method-static))
|
|
2144 (error "Cannot `call-next-method' except in :primary or :static methods")
|
|
2145 )
|
|
2146 (let ((newargs (or replacement-args eieio-generic-call-arglst))
|
|
2147 (next (car eieio-generic-call-next-method-list))
|
|
2148 )
|
|
2149 (if (or (not next) (not (car next)))
|
|
2150 (apply 'no-next-method (car newargs) (cdr newargs))
|
|
2151 (let* ((eieio-generic-call-next-method-list
|
|
2152 (cdr eieio-generic-call-next-method-list))
|
|
2153 (scoped-class (cdr next))
|
|
2154 (fcn (car next))
|
|
2155 )
|
|
2156 (apply fcn newargs)
|
|
2157 ))))
|
|
2158
|
|
2159 ;;;
|
|
2160 ;; eieio-method-tree : eieiomt-
|
|
2161 ;;
|
|
2162 ;; Stored as eieio-method-tree in property list of a generic method
|
|
2163 ;;
|
|
2164 ;; (eieio-method-tree . [BEFORE PRIMARY AFTER
|
|
2165 ;; genericBEFORE genericPRIMARY genericAFTER])
|
|
2166 ;; and
|
|
2167 ;; (eieio-method-obarray . [BEFORE PRIMARY AFTER
|
|
2168 ;; genericBEFORE genericPRIMARY genericAFTER])
|
|
2169 ;; where the association is a vector.
|
|
2170 ;; (aref 0 -- all static methods.
|
|
2171 ;; (aref 1 -- all methods classified as :before
|
|
2172 ;; (aref 2 -- all methods classified as :primary
|
|
2173 ;; (aref 3 -- all methods classified as :after
|
|
2174 ;; (aref 4 -- a generic classified as :before
|
|
2175 ;; (aref 5 -- a generic classified as :primary
|
|
2176 ;; (aref 6 -- a generic classified as :after
|
|
2177 ;;
|
|
2178 (defvar eieiomt-optimizing-obarray nil
|
|
2179 "While mapping atoms, this contain the obarray being optimized.")
|
|
2180
|
|
2181 (defun eieiomt-install (method-name)
|
|
2182 "Install the method tree, and obarray onto METHOD-NAME.
|
|
2183 Do not do the work if they already exist."
|
|
2184 (let ((emtv (get method-name 'eieio-method-tree))
|
|
2185 (emto (get method-name 'eieio-method-obarray)))
|
|
2186 (if (or (not emtv) (not emto))
|
|
2187 (progn
|
|
2188 (setq emtv (put method-name 'eieio-method-tree
|
|
2189 (make-vector method-num-slots nil))
|
|
2190 emto (put method-name 'eieio-method-obarray
|
|
2191 (make-vector method-num-slots nil)))
|
|
2192 (aset emto 0 (make-vector 11 0))
|
|
2193 (aset emto 1 (make-vector 11 0))
|
|
2194 (aset emto 2 (make-vector 41 0))
|
|
2195 (aset emto 3 (make-vector 11 0))
|
|
2196 ))))
|
|
2197
|
|
2198 (defun eieiomt-add (method-name method key class)
|
|
2199 "Add to METHOD-NAME the forms METHOD in a call position KEY for CLASS.
|
|
2200 METHOD-NAME is the name created by a call to `defgeneric'.
|
|
2201 METHOD are the forms for a given implementation.
|
|
2202 KEY is an integer (see comment in eieio.el near this function) which
|
|
2203 is associated with the :static :before :primary and :after tags.
|
|
2204 It also indicates if CLASS is defined or not.
|
|
2205 CLASS is the class this method is associated with."
|
|
2206 (if (or (> key method-num-slots) (< key 0))
|
|
2207 (error "Eieiomt-add: method key error!"))
|
|
2208 (let ((emtv (get method-name 'eieio-method-tree))
|
|
2209 (emto (get method-name 'eieio-method-obarray)))
|
|
2210 ;; Make sure the method tables are available.
|
|
2211 (if (or (not emtv) (not emto))
|
|
2212 (error "Programmer error: eieiomt-add"))
|
|
2213 ;; only add new cells on if it doesn't already exist!
|
|
2214 (if (assq class (aref emtv key))
|
|
2215 (setcdr (assq class (aref emtv key)) method)
|
|
2216 (aset emtv key (cons (cons class method) (aref emtv key))))
|
|
2217 ;; Add function definition into newly created symbol, and store
|
|
2218 ;; said symbol in the correct obarray, otherwise use the
|
|
2219 ;; other array to keep this stuff
|
|
2220 (if (< key method-num-lists)
|
|
2221 (let ((nsym (intern (symbol-name class) (aref emto key))))
|
|
2222 (fset nsym method)))
|
|
2223 ;; Now optimize the entire obarray
|
|
2224 (if (< key method-num-lists)
|
|
2225 (let ((eieiomt-optimizing-obarray (aref emto key)))
|
|
2226 ;; @todo - Is this overkill? Should we just clear the symbol?
|
|
2227 (mapatoms 'eieiomt-sym-optimize eieiomt-optimizing-obarray)))
|
|
2228 ))
|
|
2229
|
|
2230 (defun eieiomt-next (class)
|
|
2231 "Return the next parent class for CLASS.
|
|
2232 If CLASS is a superclass, return variable `eieio-default-superclass'. If CLASS
|
|
2233 is variable `eieio-default-superclass' then return nil. This is different from
|
|
2234 function `class-parent' as class parent returns nil for superclasses. This
|
|
2235 function performs no type checking!"
|
|
2236 ;; No type-checking because all calls are made from functions which
|
|
2237 ;; are safe and do checking for us.
|
|
2238 (or (class-parents-fast class)
|
|
2239 (if (eq class 'eieio-default-superclass)
|
|
2240 nil
|
|
2241 '(eieio-default-superclass))))
|
|
2242
|
|
2243 (defun eieiomt-sym-optimize (s)
|
|
2244 "Find the next class above S which has a function body for the optimizer."
|
|
2245 ;; (message "Optimizing %S" s)
|
|
2246 (let* ((es (intern-soft (symbol-name s))) ;external symbol of class
|
|
2247 (io (class-method-invocation-order es))
|
|
2248 (ov nil)
|
|
2249 (cont t))
|
|
2250 ;; This converts ES from a single symbol to a list of parent classes.
|
|
2251 (setq es (eieiomt-next es))
|
|
2252 ;; Loop over ES, then it's children individually.
|
|
2253 ;; We can have multiple hits only at one level of the parent tree.
|
|
2254 (while (and es cont)
|
|
2255 (setq ov (intern-soft (symbol-name (car es)) eieiomt-optimizing-obarray))
|
|
2256 (if (fboundp ov)
|
|
2257 (progn
|
|
2258 (set s ov) ;store ov as our next symbol
|
|
2259 (setq cont nil))
|
|
2260 (if (eq io :depth-first)
|
|
2261 ;; Pre-pend the subclasses of (car es) so we get
|
|
2262 ;; DEPTH FIRST optimization.
|
|
2263 (setq es (append (eieiomt-next (car es)) (cdr es)))
|
|
2264 ;; Else, we are breadth first.
|
|
2265 ;; (message "Class %s is breadth first" es)
|
|
2266 (setq es (append (cdr es) (eieiomt-next (car es))))
|
|
2267 )))
|
|
2268 ;; If there is no nearest call, then set our value to nil
|
|
2269 (if (not es) (set s nil))
|
|
2270 ))
|
|
2271
|
|
2272 (defun eieio-generic-form (method key class)
|
|
2273 "Return the lambda form belonging to METHOD using KEY based upon CLASS.
|
|
2274 If CLASS is not a class then use `generic' instead. If class has no
|
|
2275 form, but has a parent class, then trace to that parent class. The
|
|
2276 first time a form is requested from a symbol, an optimized path is
|
|
2277 memoized for future faster use."
|
|
2278 (let ((emto (aref (get method 'eieio-method-obarray)
|
|
2279 (if class key (+ key 3)))))
|
|
2280 (if (class-p class)
|
|
2281 ;; 1) find our symbol
|
|
2282 (let ((cs (intern-soft (symbol-name class) emto)))
|
|
2283 (if (not cs)
|
|
2284 ;; 2) If there isn't one, then make one.
|
|
2285 ;; This can be slow since it only occurs once
|
|
2286 (progn
|
|
2287 (setq cs (intern (symbol-name class) emto))
|
|
2288 ;; 2.1) Cache it's nearest neighbor with a quick optimize
|
|
2289 ;; which should only occur once for this call ever
|
|
2290 (let ((eieiomt-optimizing-obarray emto))
|
|
2291 (eieiomt-sym-optimize cs))))
|
|
2292 ;; 3) If it's bound return this one.
|
|
2293 (if (fboundp cs)
|
|
2294 (cons cs (aref (class-v class) class-symbol))
|
|
2295 ;; 4) If it's not bound then this variable knows something
|
|
2296 (if (symbol-value cs)
|
|
2297 (progn
|
|
2298 ;; 4.1) This symbol holds the next class in it's value
|
|
2299 (setq class (symbol-value cs)
|
|
2300 cs (intern-soft (symbol-name class) emto))
|
|
2301 ;; 4.2) The optimizer should always have chosen a
|
|
2302 ;; function-symbol
|
|
2303 ;;(if (fboundp cs)
|
|
2304 (cons cs (aref (class-v (intern (symbol-name class)))
|
|
2305 class-symbol))
|
|
2306 ;;(error "EIEIO optimizer: erratic data loss!"))
|
|
2307 )
|
|
2308 ;; There never will be a funcall...
|
|
2309 nil)))
|
|
2310 ;; for a generic call, what is a list, is the function body we want.
|
|
2311 (let ((emtl (aref (get method 'eieio-method-tree)
|
|
2312 (if class key (+ key 3)))))
|
|
2313 (if emtl
|
|
2314 ;; The car of EMTL is supposed to be a class, which in this
|
|
2315 ;; case is nil, so skip it.
|
|
2316 (cons (cdr (car emtl)) nil)
|
|
2317 nil)))))
|
|
2318
|
|
2319 ;;;
|
|
2320 ;; Way to assign slots based on a list. Used for constructors, or
|
|
2321 ;; even resetting an object at run-time
|
|
2322 ;;
|
|
2323 (defun eieio-set-defaults (obj &optional set-all)
|
|
2324 "Take object OBJ, and reset all slots to their defaults.
|
|
2325 If SET-ALL is non-nil, then when a default is nil, that value is
|
|
2326 reset. If SET-ALL is nil, the slots are only reset if the default is
|
|
2327 not nil."
|
|
2328 (let ((scoped-class (aref obj object-class))
|
|
2329 (eieio-initializing-object t)
|
|
2330 (pub (aref (class-v (aref obj object-class)) class-public-a)))
|
|
2331 (while pub
|
|
2332 (let ((df (eieio-oref-default obj (car pub))))
|
|
2333 (if (or df set-all)
|
|
2334 (eieio-oset obj (car pub) df)))
|
|
2335 (setq pub (cdr pub)))))
|
|
2336
|
|
2337 (defun eieio-initarg-to-attribute (class initarg)
|
|
2338 "For CLASS, convert INITARG to the actual attribute name.
|
|
2339 If there is no translation, pass it in directly (so we can cheat if
|
|
2340 need be.. May remove that later...)"
|
|
2341 (let ((tuple (assoc initarg (aref (class-v class) class-initarg-tuples))))
|
|
2342 (if tuple
|
|
2343 (cdr tuple)
|
|
2344 nil)))
|
|
2345
|
|
2346 (defun eieio-attribute-to-initarg (class attribute)
|
|
2347 "In CLASS, convert the ATTRIBUTE into the corresponding init argument tag.
|
|
2348 This is usually a symbol that starts with `:'."
|
|
2349 (let ((tuple (rassoc attribute (aref (class-v class) class-initarg-tuples))))
|
|
2350 (if tuple
|
|
2351 (car tuple)
|
|
2352 nil)))
|
|
2353
|
|
2354
|
|
2355 ;;; Here are some special types of errors
|
|
2356 ;;
|
|
2357 (intern "no-method-definition")
|
|
2358 (put 'no-method-definition 'error-conditions '(no-method-definition error))
|
|
2359 (put 'no-method-definition 'error-message "No method definition")
|
|
2360
|
|
2361 (intern "no-next-method")
|
|
2362 (put 'no-next-method 'error-conditions '(no-next-method error))
|
|
2363 (put 'no-next-method 'error-message "No next method")
|
|
2364
|
|
2365 (intern "invalid-slot-name")
|
|
2366 (put 'invalid-slot-name 'error-conditions '(invalid-slot-name error))
|
|
2367 (put 'invalid-slot-name 'error-message "Invalid slot name")
|
|
2368
|
|
2369 (intern "invalid-slot-type")
|
|
2370 (put 'invalid-slot-type 'error-conditions '(invalid-slot-type error nil))
|
|
2371 (put 'invalid-slot-type 'error-message "Invalid slot type")
|
|
2372
|
|
2373 (intern "unbound-slot")
|
|
2374 (put 'unbound-slot 'error-conditions '(unbound-slot error nil))
|
|
2375 (put 'unbound-slot 'error-message "Unbound slot")
|
|
2376
|
|
2377 ;;; Here are some CLOS items that need the CL package
|
|
2378 ;;
|
|
2379
|
|
2380 (defsetf slot-value (obj slot) (store) (list 'eieio-oset obj slot store))
|
|
2381 (defsetf eieio-oref (obj slot) (store) (list 'eieio-oset obj slot store))
|
|
2382
|
|
2383 ;; The below setf method was written by Arnd Kohrs <kohrs@acm.org>
|
|
2384 (define-setf-method oref (obj slot)
|
|
2385 (let ((obj-temp (gensym))
|
|
2386 (slot-temp (gensym))
|
|
2387 (store-temp (gensym)))
|
|
2388 (list (list obj-temp slot-temp)
|
|
2389 (list obj `(quote ,slot))
|
|
2390 (list store-temp)
|
|
2391 (list 'set-slot-value obj-temp slot-temp
|
|
2392 store-temp)
|
|
2393 (list 'slot-value obj-temp slot-temp))))
|
|
2394
|
|
2395
|
|
2396 ;;;
|
|
2397 ;; We want all objects created by EIEIO to have some default set of
|
|
2398 ;; behaviours so we can create object utilities, and allow various
|
|
2399 ;; types of error checking. To do this, create the default EIEIO
|
|
2400 ;; class, and when no parent class is specified, use this as the
|
|
2401 ;; default. (But don't store it in the other classes as the default,
|
|
2402 ;; allowing for transparent support.)
|
|
2403 ;;
|
|
2404
|
|
2405 (defclass eieio-default-superclass nil
|
|
2406 nil
|
|
2407 "Default parent class for classes with no specified parent class.
|
|
2408 Its slots are automatically adopted by classes with no specified
|
|
2409 parents. This class is not stored in the `parent' slot of a class vector."
|
|
2410 :abstract t)
|
|
2411
|
|
2412 (defalias 'standard-class 'eieio-default-superclass)
|
|
2413
|
|
2414 (defgeneric constructor (class newname &rest slots)
|
|
2415 "Default constructor for CLASS `eieio-defualt-superclass'.")
|
|
2416
|
|
2417 (defmethod constructor :static
|
|
2418 ((class eieio-default-superclass) newname &rest slots)
|
|
2419 "Default constructor for CLASS `eieio-defualt-superclass'.
|
|
2420 NEWNAME is the name to be given to the constructed object.
|
|
2421 SLOTS are the initialization slots used by `shared-initialize'.
|
|
2422 This static method is called when an object is constructed.
|
|
2423 It allocates the vector used to represent an EIEIO object, and then
|
|
2424 calls `shared-initialize' on that object."
|
|
2425 (let* ((new-object (copy-sequence (aref (class-v class)
|
|
2426 class-default-object-cache))))
|
|
2427 ;; Update the name for the newly created object.
|
|
2428 (aset new-object object-name newname)
|
|
2429 ;; Call the initialize method on the new object with the slots
|
|
2430 ;; that were passed down to us.
|
|
2431 (initialize-instance new-object slots)
|
|
2432 ;; Return the created object.
|
|
2433 new-object))
|
|
2434
|
|
2435 (defgeneric shared-initialize (obj slots)
|
|
2436 "Set slots of OBJ with SLOTS which is a list of name/value pairs.
|
|
2437 Called from the constructor routine.")
|
|
2438
|
|
2439 (defmethod shared-initialize ((obj eieio-default-superclass) slots)
|
|
2440 "Set slots of OBJ with SLOTS which is a list of name/value pairs.
|
|
2441 Called from the constructor routine."
|
|
2442 (let ((scoped-class (aref obj object-class)))
|
|
2443 (while slots
|
|
2444 (let ((rn (eieio-initarg-to-attribute (object-class-fast obj)
|
|
2445 (car slots))))
|
|
2446 (if (not rn)
|
|
2447 (slot-missing obj (car slots) 'oset (car (cdr slots)))
|
|
2448 (eieio-oset obj rn (car (cdr slots)))))
|
|
2449 (setq slots (cdr (cdr slots))))))
|
|
2450
|
|
2451 (defgeneric initialize-instance (this &optional slots)
|
|
2452 "Constructs the new object THIS based on SLOTS.")
|
|
2453
|
|
2454 (defmethod initialize-instance ((this eieio-default-superclass)
|
|
2455 &optional slots)
|
|
2456 "Constructs the new object THIS based on SLOTS.
|
|
2457 SLOTS is a tagged list where odd numbered elements are tags, and
|
|
2458 even numbered elements are the values to store in the tagged slot. If
|
|
2459 you overload the `initialize-instance', there you will need to call
|
|
2460 `shared-initialize' yourself, or you can call `call-next-method' to
|
|
2461 have this constructor called automatically. If these steps are not
|
|
2462 taken, then new objects of your class will not have their values
|
|
2463 dynamically set from SLOTS."
|
|
2464 ;; First, see if any of our defaults are `lambda', and
|
|
2465 ;; re-evaluate them and apply the value to our slots.
|
|
2466 (let* ((scoped-class (class-v (aref this object-class)))
|
|
2467 (slot (aref scoped-class class-public-a))
|
|
2468 (defaults (aref scoped-class class-public-d)))
|
|
2469 (while slot
|
|
2470 (setq slot (cdr slot)
|
|
2471 defaults (cdr defaults))))
|
|
2472 ;; Shared initialize will parse our slots for us.
|
|
2473 (shared-initialize this slots))
|
|
2474
|
|
2475 (defgeneric slot-missing (object slot-name operation &optional new-value)
|
|
2476 "Method invoked when an attempt to access a slot in OBJECT fails.")
|
|
2477
|
|
2478 (defmethod slot-missing ((object eieio-default-superclass) slot-name
|
|
2479 operation &optional new-value)
|
|
2480 "Method invoked when an attempt to access a slot in OBJECT fails.
|
|
2481 SLOT-NAME is the name of the failed slot, OPERATION is the type of access
|
|
2482 that was requested, and optional NEW-VALUE is the value that was desired
|
|
2483 to be set.
|
|
2484
|
|
2485 This method is called from `oref', `oset', and other functions which
|
|
2486 directly reference slots in EIEIO objects."
|
|
2487 (signal 'invalid-slot-name (list (object-name object)
|
|
2488 slot-name)))
|
|
2489
|
|
2490 (defgeneric slot-unbound (object class slot-name fn)
|
|
2491 "Slot unbound is invoked during an attempt to reference an unbound slot.")
|
|
2492
|
|
2493 (defmethod slot-unbound ((object eieio-default-superclass)
|
|
2494 class slot-name fn)
|
|
2495 "Slot unbound is invoked during an attempt to reference an unbound slot.
|
|
2496 OBJECT is the instance of the object being reference. CLASS is the
|
|
2497 class of OBJECT, and SLOT-NAME is the offending slot. This function
|
|
2498 throws the signal `unbound-slot'. You can overload this function and
|
|
2499 return the value to use in place of the unbound value.
|
|
2500 Argument FN is the function signaling this error.
|
|
2501 Use `slot-boundp' to determine if a slot is bound or not.
|
|
2502
|
|
2503 In CLOS, the argument list is (CLASS OBJECT SLOT-NAME), but
|
|
2504 EIEIO can only dispatch on the first argument, so the first two are swapped."
|
|
2505 (signal 'unbound-slot (list (class-name class) (object-name object)
|
|
2506 slot-name fn)))
|
|
2507
|
|
2508 (defgeneric no-applicable-method (object method &rest args)
|
|
2509 "Called if there are no implementations for OBJECT in METHOD.")
|
|
2510
|
|
2511 (defmethod no-applicable-method ((object eieio-default-superclass)
|
|
2512 method &rest args)
|
|
2513 "Called if there are no implementations for OBJECT in METHOD.
|
|
2514 OBJECT is the object which has no method implementation.
|
|
2515 ARGS are the arguments that were passed to METHOD.
|
|
2516
|
|
2517 Implement this for a class to block this signal. The return
|
|
2518 value becomes the return value of the original method call."
|
|
2519 (signal 'no-method-definition (list method (object-name object)))
|
|
2520 )
|
|
2521
|
|
2522 (defgeneric no-next-method (object &rest args)
|
|
2523 "Called from `call-next-method' when no additional methods are available.")
|
|
2524
|
|
2525 (defmethod no-next-method ((object eieio-default-superclass)
|
|
2526 &rest args)
|
|
2527 "Called from `call-next-method' when no additional methods are available.
|
|
2528 OBJECT is othe object being called on `call-next-method'.
|
|
2529 ARGS are the arguments it is called by.
|
|
2530 This method signals `no-next-method' by default. Override this
|
|
2531 method to not throw an error, and it's return value becomes the
|
|
2532 return value of `call-next-method'."
|
|
2533 (signal 'no-next-method (list (object-name object) args))
|
|
2534 )
|
|
2535
|
|
2536 (defgeneric clone (obj &rest params)
|
|
2537 "Make a copy of OBJ, and then supply PARAMS.
|
|
2538 PARAMS is a parameter list of the same form used by `initialize-instance'.
|
|
2539
|
|
2540 When overloading `clone', be sure to call `call-next-method'
|
|
2541 first and modify the returned object.")
|
|
2542
|
|
2543 (defmethod clone ((obj eieio-default-superclass) &rest params)
|
|
2544 "Make a copy of OBJ, and then apply PARAMS."
|
|
2545 (let ((nobj (copy-sequence obj))
|
|
2546 (nm (aref obj object-name))
|
|
2547 (passname (and params (stringp (car params))))
|
|
2548 (num 1))
|
|
2549 (if params (shared-initialize nobj (if passname (cdr params) params)))
|
|
2550 (if (not passname)
|
|
2551 (save-match-data
|
|
2552 (if (string-match "-\\([0-9]+\\)" nm)
|
|
2553 (setq num (1+ (string-to-number (match-string 1 nm)))
|
|
2554 nm (substring nm 0 (match-beginning 0))))
|
|
2555 (aset nobj object-name (concat nm "-" (int-to-string num))))
|
|
2556 (aset nobj object-name (car params)))
|
|
2557 nobj))
|
|
2558
|
|
2559 (defgeneric destructor (this &rest params)
|
|
2560 "Destructor for cleaning up any dynamic links to our object.")
|
|
2561
|
|
2562 (defmethod destructor ((this eieio-default-superclass) &rest params)
|
|
2563 "Destructor for cleaning up any dynamic links to our object.
|
|
2564 Argument THIS is the object being destroyed. PARAMS are additional
|
|
2565 ignored parameters."
|
|
2566 ;; No cleanup... yet.
|
|
2567 )
|
|
2568
|
|
2569 (defgeneric object-print (this &rest strings)
|
|
2570 "Pretty printer for object THIS. Call function `object-name' with STRINGS.
|
|
2571
|
|
2572 It is sometimes useful to put a summary of the object into the
|
|
2573 default #<notation> string when using eieio browsing tools.
|
|
2574 Implement this method to customize the summary.")
|
|
2575
|
|
2576 (defmethod object-print ((this eieio-default-superclass) &rest strings)
|
|
2577 "Pretty printer for object THIS. Call function `object-name' with STRINGS.
|
|
2578 The default method for printing object THIS is to use the
|
|
2579 function `object-name'.
|
|
2580
|
|
2581 It is sometimes useful to put a summary of the object into the
|
|
2582 default #<notation> string when using eieio browsing tools.
|
|
2583
|
|
2584 Implement this function and specify STRINGS in a call to
|
|
2585 `call-next-method' to provide additional summary information.
|
|
2586 When passing in extra strings from child classes, always remember
|
|
2587 to prepend a space."
|
|
2588 (object-name this (apply 'concat strings)))
|
|
2589
|
|
2590 (defvar eieio-print-depth 0
|
|
2591 "When printing, keep track of the current indentation depth.")
|
|
2592
|
|
2593 (defgeneric object-write (this &optional comment)
|
|
2594 "Write out object THIS to the current stream.
|
|
2595 Optional COMMENDS will add comments to the beginning of the output.")
|
|
2596
|
|
2597 (defmethod object-write ((this eieio-default-superclass) &optional comment)
|
|
2598 "Write object THIS out to the current stream.
|
|
2599 This writes out the vector version of this object. Complex and recursive
|
|
2600 object are discouraged from being written.
|
|
2601 If optional COMMENT is non-nil, include comments when outputting
|
|
2602 this object."
|
|
2603 (when comment
|
|
2604 (princ ";; Object ")
|
|
2605 (princ (object-name-string this))
|
|
2606 (princ "\n")
|
|
2607 (princ comment)
|
|
2608 (princ "\n"))
|
|
2609 (let* ((cl (object-class this))
|
|
2610 (cv (class-v cl)))
|
|
2611 ;; Now output readable lisp to recreate this object
|
|
2612 ;; It should look like this:
|
|
2613 ;; (<constructor> <name> <slot> <slot> ... )
|
|
2614 ;; Each slot's slot is writen using its :writer.
|
|
2615 (princ (make-string (* eieio-print-depth 2) ? ))
|
|
2616 (princ "(")
|
|
2617 (princ (symbol-name (class-constructor (object-class this))))
|
|
2618 (princ " \"")
|
|
2619 (princ (object-name-string this))
|
|
2620 (princ "\"\n")
|
|
2621 ;; Loop over all the public slots
|
|
2622 (let ((publa (aref cv class-public-a))
|
|
2623 (publd (aref cv class-public-d))
|
|
2624 (publp (aref cv class-public-printer))
|
|
2625 (eieio-print-depth (1+ eieio-print-depth)))
|
|
2626 (while publa
|
|
2627 (when (slot-boundp this (car publa))
|
|
2628 (let ((i (class-slot-initarg cl (car publa)))
|
|
2629 (v (eieio-oref this (car publa)))
|
|
2630 )
|
|
2631 (unless (or (not i) (equal v (car publd)))
|
|
2632 (princ (make-string (* eieio-print-depth 2) ? ))
|
|
2633 (princ (symbol-name i))
|
|
2634 (princ " ")
|
|
2635 (if (car publp)
|
|
2636 ;; Use our public printer
|
|
2637 (funcall (car publp) v)
|
|
2638 ;; Use our generic override prin1 function.
|
|
2639 (eieio-override-prin1 v))
|
|
2640 (princ "\n"))))
|
|
2641 (setq publa (cdr publa) publd (cdr publd)
|
|
2642 publp (cdr publp)))
|
|
2643 (princ (make-string (* eieio-print-depth 2) ? )))
|
|
2644 (princ ")\n")))
|
|
2645
|
|
2646 (defun eieio-override-prin1 (thing)
|
|
2647 "Perform a prin1 on THING taking advantage of object knowledge."
|
|
2648 (cond ((eieio-object-p thing)
|
|
2649 (object-write thing))
|
|
2650 ((listp thing)
|
|
2651 (eieio-list-prin1 thing))
|
|
2652 ((class-p thing)
|
|
2653 (princ (class-name thing)))
|
|
2654 ((symbolp thing)
|
|
2655 (princ (concat "'" (symbol-name thing))))
|
|
2656 (t (prin1 thing))))
|
|
2657
|
|
2658 (defun eieio-list-prin1 (list)
|
|
2659 "Display LIST where list may contain objects."
|
|
2660 (if (not (eieio-object-p (car list)))
|
|
2661 (progn
|
|
2662 (princ "'")
|
|
2663 (prin1 list))
|
|
2664 (princ "(list ")
|
|
2665 (if (eieio-object-p (car list)) (princ "\n "))
|
|
2666 (while list
|
|
2667 (if (eieio-object-p (car list))
|
|
2668 (object-write (car list))
|
|
2669 (princ "'")
|
|
2670 (prin1 (car list)))
|
|
2671 (princ " ")
|
|
2672 (setq list (cdr list)))
|
|
2673 (princ (make-string (* eieio-print-depth 2) ? ))
|
|
2674 (princ ")")))
|
|
2675
|
|
2676
|
|
2677 ;;; Unimplemented functions from CLOS
|
|
2678 ;;
|
|
2679 (defun change-class (obj class)
|
|
2680 "Change the class of OBJ to type CLASS.
|
|
2681 This may create or delete slots, but does not affect the return value
|
|
2682 of `eq'."
|
|
2683 (error "Eieio: `change-class' is unimplemented"))
|
|
2684
|
|
2685 )
|
|
2686
|
|
2687
|
|
2688 ;;; Interfacing with edebug
|
|
2689 ;;
|
|
2690 (defun eieio-edebug-prin1-to-string (object &optional noescape)
|
|
2691 "Display eieio OBJECT in fancy format. Overrides the edebug default.
|
|
2692 Optional argument NOESCAPE is passed to `prin1-to-string' when appropriate."
|
|
2693 (cond ((class-p object) (class-name object))
|
|
2694 ((eieio-object-p object) (object-print object))
|
|
2695 ((and (listp object) (or (class-p (car object))
|
|
2696 (eieio-object-p (car object))))
|
|
2697 (concat "(" (mapconcat 'eieio-edebug-prin1-to-string object " ") ")"))
|
|
2698 (t (prin1-to-string object noescape))))
|
|
2699
|
|
2700 (add-hook 'edebug-setup-hook
|
|
2701 (lambda ()
|
|
2702 (def-edebug-spec defmethod
|
|
2703 (&define ; this means we are defining something
|
|
2704 [&or name ("setf" :name setf name)]
|
|
2705 ;; ^^ This is the methods symbol
|
|
2706 [ &optional symbolp ] ; this is key :before etc
|
|
2707 list ; arguments
|
|
2708 [ &optional stringp ] ; documentation string
|
|
2709 def-body ; part to be debugged
|
|
2710 ))
|
|
2711 ;; The rest of the macros
|
|
2712 (def-edebug-spec oref (form quote))
|
|
2713 (def-edebug-spec oref-default (form quote))
|
|
2714 (def-edebug-spec oset (form quote form))
|
|
2715 (def-edebug-spec oset-default (form quote form))
|
|
2716 (def-edebug-spec class-v form)
|
|
2717 (def-edebug-spec class-p form)
|
|
2718 (def-edebug-spec eieio-object-p form)
|
|
2719 (def-edebug-spec class-constructor form)
|
|
2720 (def-edebug-spec generic-p form)
|
|
2721 (def-edebug-spec with-slots (list list def-body))
|
|
2722 ;; I suspect this isn't the best way to do this, but when
|
|
2723 ;; cust-print was used on my system all my objects
|
|
2724 ;; appeared as "#1 =" which was not useful. This allows
|
|
2725 ;; edebug to print my objects in the nice way they were
|
|
2726 ;; meant to with `object-print' and `class-name'
|
|
2727 ;; (defalias 'edebug-prin1-to-string 'eieio-edebug-prin1-to-string)
|
|
2728 )
|
|
2729 )
|
|
2730
|
|
2731 ;;; Interfacing with imenu in emacs lisp mode
|
|
2732 ;; (Only if the expression is defined)
|
|
2733 ;;
|
|
2734 (if (eval-when-compile (boundp 'list-imenu-generic-expression))
|
|
2735 (progn
|
|
2736
|
|
2737 (defun eieio-update-lisp-imenu-expression ()
|
|
2738 "Examine `lisp-imenu-generic-expression' and modify it to find `defmethod'."
|
|
2739 (let ((exp lisp-imenu-generic-expression))
|
|
2740 (while exp
|
|
2741 ;; it's of the form '( ( title expr indx ) ... )
|
|
2742 (let* ((subcar (cdr (car exp)))
|
|
2743 (substr (car subcar)))
|
|
2744 (if (and (not (string-match "|method\\\\" substr))
|
|
2745 (string-match "|advice\\\\" substr))
|
|
2746 (setcar subcar
|
|
2747 (replace-match "|advice\\|method\\" t t substr 0))))
|
|
2748 (setq exp (cdr exp)))))
|
|
2749
|
|
2750 (eieio-update-lisp-imenu-expression)
|
|
2751
|
|
2752 ))
|
|
2753
|
|
2754 ;;; Autoloading some external symbols, and hooking into the help system
|
|
2755 ;;
|
|
2756
|
|
2757 (autoload 'eieio-help-mode-augmentation-maybee "eieio-opt" "For buffers thrown into help mode, augment for eieio.")
|
|
2758 (autoload 'eieio-browse "eieio-opt" "Create an object browser window" t)
|
|
2759 (autoload 'eieio-describe-class "eieio-opt" "Describe CLASS defined by a string or symbol" t)
|
|
2760 (autoload 'eieio-describe-constructor "eieio-opt" "Describe the constructor function FCN." t)
|
|
2761 (autoload 'describe-class "eieio-opt" "Describe CLASS defined by a string or symbol" t)
|
|
2762 (autoload 'eieio-describe-generic "eieio-opt" "Describe GENERIC defined by a string or symbol" t)
|
|
2763 (autoload 'describe-generic "eieio-opt" "Describe GENERIC defined by a string or symbol" t)
|
|
2764
|
|
2765 (autoload 'customize-object "eieio-custom" "Create a custom buffer editing OBJ.")
|
|
2766
|
|
2767 (provide 'eieio)
|
|
2768
|
|
2769 ;; Local variables:
|
|
2770 ;; byte-compile-warnings: (not cl-functions)
|
|
2771 ;; End:
|
|
2772
|
|
2773 ;;; eieio ends here
|